¿Cómo enumero todos los archivos en un directorio excepto aquellos con extensiones especificadas?


28

Supongamos que tengo una carpeta que contiene .txt , .pdf y otros archivos. Me gustaría enumerar los "otros" archivos (es decir, archivos que no tienen las extensiones .txt o .pdf ). ¿Tienes algún consejo sobre cómo hacer esto?

Sé cómo enumerar archivos que no tienen una extensión determinada. Por ejemplo, si quiero enumerar todos los archivos excepto los archivos .txt , entonces

find -not -iname "*.txt"

o

ls | grep -v '\.txt$' | column

parece funcionar Pero, ¿cómo puedo enumerar todo excepto los archivos .txt o .pdf ? Parece que necesito usar algún tipo de "o" lógico en findo grep.


2
Tenga en cuenta que el comportamiento de lsvs findvs globbing puede diferir para los archivos de puntos ocultos.
jw013

1
Otra cosa a tener en cuenta: findatravesará subdirectorios, como un recursivo ls. Use -maxdepth 1con findpara que se comporte más ls.
jw013

Entonces, no recursivo, ¿solo enumera los archivos en el directorio actual?
Margarita

Respuestas:


28

Suponiendo que uno tenga una versión apropiada de ls, esta es posiblemente la forma más simple:

ls -I "*.txt" -I "*.pdf"

Si desea recorrer en iteración todos los subdirectorios:

ls -I "*.txt" -I "*.pdf" -R

8
Las lsopciones de GNU no son portátiles.
bahamat

44
lsde todos modos no pertenece realmente a los scripts portátiles, así que he estado asumiendo que el OP solo pregunta sobre el uso interactivo.
jw013

1
¿Por qué ls no es portátil? ¿Qué debo usar entonces?
Freedo

28

Encuentra apoyos -o

find . ! '(' -name '*.txt' -o -name '*.pdf' ')'

Necesita el paréntesis para que la precedencia sea correcta. Find hace muchas cosas; Sugiero leer a través de su página de manual.

También puede hacer un o en grep(pero realmente, no debe analizar la salida dels )

ls | grep -Ev '\.(txt|pdf)$' | column

1
¡Gracias! ¿Por qué no debería analizar la salida de ls?
Andrew

66
@Andrew primero, porque es frágil (considere un nombre de archivo con una nueva línea, sí, ese es un nombre de archivo válido, encuentre -print0 / -exec / -delete / etc. Evite ese problema); segundo, porque generalmente hay una manera más fácil.
derobert

Además de la página de findmanual, recomiendo de todo corazón los artículos sobre Unix Power Tools find, como docstore.mik.ua/orelly/unix3/upt/ch09_06.htm y docstore.mik.ua/orelly/unix3/upt/ch09_12.htm
Comodín

Solo para ayudar a decodificar la declaración para los humanos:find . NOT ( *.txt OR *.pdf )
wisbucky

12

Con bashglobbing extendido (activar con shopt -s extglob), el glob !(*.txt|*.pdf)debería funcionar. Puede pasar este globo directamente a cualquier comando que tome argumentos de archivo, incluidos, entre otros ls.


1
+1 pero si tiene subdirectorios, su contenido también aparecerá en la lista; use -dpara evitar eso:ls -d !(*.txt|*.pdf)
legends2k

Gracias, estaba buscando exactamente la sintaxis para aceptar varios archivos, esto encajaría bien aquí stackoverflow.com/questions/216995/…
Freedo

6

En zshcon extendedglob:

print -rl -- *~*.(txt|pdf)

o

print -rl -- ^*.(txt|pdf)

O con kshglob(sí, eso es ksh globbing no "bash extended globbing"):

print -rl -- !(*.txt|*.pdf)

Sin embargo, recuerde que también excluyen los archivos de puntos.

ksh93 tiene la característica FIGNORE(mis):

FIGNORE='@(.|..|*.txt|*.pdf)'
printf '%s\n' *


3

Según lo sugerido por derobert, su mejor opción es usar find. Sin embargo, de hecho , puede utilizar el resultado en una tubería con otros comandos.

GNU (y algunos BSD) findadmiten el -print0predicado que le dice que imprima el nombre de archivo terminado por un carácter NUL , cuyo carácter no está permitido dentro de un nombre de archivo y garantiza que no habrá una colisión. Se pueden indicar otros comandos para usar el NUL como su delimitador de entrada.

El más importante de los cuales es GNU xargs, que ejecuta el comando que especifique y le pasa la lista de archivos como argumentos de línea de comando. Desea ejecutar xargs -r0conjuntamente con find's -print0Por ejemplo:

find . -type f ! \( -name \*.pdf -o -name \*.txt \) -print0 | xargs -r0 ls -ld

Esto imprime de forma segura una lista larga de todos los archivos pdf y txt , incluidos aquellos con espacios o caracteres no imprimibles en el nombre.

También puede usarlo con GNU de la tarsiguiente manera:

tar -zcf myarchive.tar.gz --null --files-from <(
  find . -type f ! -name \*.tar.gz -print0)

Esto crea un archivo tar.gz de todos los archivos cuyos nombres no terminan en .tar.gz

rsynctambién acepta archivos delimitados por nulos con el -0parámetro, al igual que muchos otros. Pero xargses el pegamento que usualmente usarás para este tipo de propósito. O eso o findla -execcaracterística.


El tarejemplo de comando es bueno. Sin embargo, para la mayoría de los propósitos, -execse ajusta mejor.
Comodín

1

Si no tienes un subdirectorio

ls !(*.pdf|*.txt)

también debería funcionar!

Pero

ls -I "*.pdf" -I "*.txt"

Es la forma común.


0

Como complemento, si usa un shell compatible con bash, puede usar la variable GLOBIGNORE para excluir los resultados de la coincidencia de patrones. Del hombre:

   GLOBIGNORE
          A colon-separated list of patterns defining the set of filenames
          to be ignored by pathname expansion.  If a filename matched by a
          pathname  expansion  pattern also matches one of the patterns in
          GLOBIGNORE, it is removed from the list of matches.

En tu caso particular:

sh$ (GLOBIGNORE='*.pdf:*.txt'; ls -d *)

Tenga en cuenta que ejecuto ese comando como un sub-shell (usando paréntesis) para no alterar la variable de entorno GLOBIGNORE de mi shell interactivo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.