Como faço para listar todos os arquivos em um diretório, exceto aqueles com extensões especificadas?

23

Suponha que eu tenha uma pasta contendo .txt , .pdf e outros arquivos. Gostaria de listar os "outros" arquivos (ou seja, arquivos que não possuem as extensões .txt ou .pdf ). Você tem algum conselho sobre como fazer isso?

Eu sei listar arquivos que não possuem uma determinada extensão. Por exemplo, se eu quiser listar todos os arquivos, exceto os arquivos .txt , então

find -not -iname "*.txt"

ou

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

parece funcionar. Mas, como posso listar tudo, exceto arquivos .txt ou .pdf ? Parece que preciso usar algum tipo de "ou" lógico em find ou grep .

    
por Andrew 04.09.2012 / 21:23

8 respostas

24

Supondo que uma tenha uma versão apropriada de ls , esta é possivelmente a maneira mais simples:

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

Se você deseja iterar em todos os subdiretórios:

ls -I "*.txt" -I "*.pdf" -R
    
por 05.09.2012 / 15:43
25

Encontre apoios -o

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

Você precisa dos parênteses para fazer a precedência correta. Encontrar faz um monte de coisas; Sugiro ler através de sua manpage.

Você também pode fazer um ou em grep (mas, na verdade, você não deve analisar a saída de ls )

ls | grep -Ev '\.(txt|pdf)$' | column
    
por 04.09.2012 / 21:29
12

Com bash extended globbing (ativado com shopt -s extglob ), o glob !(*.txt|*.pdf) deve funcionar. Você pode passar este glob diretamente para qualquer comando que receba argumentos de arquivo, incluindo, mas não limitado a, ls .

    
por 04.09.2012 / 21:28
6

Em zsh com extendedglob :

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

ou

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

Ou com kshglob (sim, isso é ksh globbing e não "bash extended globbing"):

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

Lembre-se que esses também excluem arquivos de ponto.

O ksh93 tem o recurso FIGNORE (mis):

FIGNORE='@(.|..|*.txt|*.pdf)'
printf '%s\n' *
    
por 04.09.2012 / 21:43
4
find /path/to/directory '!' -name '*.pdf' '!' -name '*.txt'

Isto é equivalente ao comando com o operador OR, devido às leis de De Morgan .

    
por 05.09.2012 / 16:22
3

Como sugerido por derobert, sua melhor aposta é usar find . No entanto, você pode usar o resultado em um pipeline com outros comandos.

GNU (e alguns BSD's) find suportam o predicado -print0 que diz para imprimir o nome do arquivo terminado por um caracter NUL , cujo caracter não é permitido dentro de um nome de arquivo e garante não haverá colisão. Outros comandos podem ser instruídos para usar o NUL como seu delimitador de entrada.

O mais importante deles é o GNU xargs , que executa o comando especificado e transmite a ele a lista de arquivos como argumentos da linha de comando. Você deseja executar xargs -r0 em conjunto com -print0 de find Por exemplo:

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

Imprime com segurança uma longa lista de diretórios de todos os arquivos pdf e txt , incluindo aqueles com espaços ou caracteres não imprimíveis no nome.

Você também pode usá-lo com o GNU tar da seguinte forma:

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

Isto constrói um arquivo tar.gz de todos os arquivos cujos nomes não terminam em .tar.gz

rsync também aceita arquivos delimitados por nulo com o parâmetro -0 , assim como vários outros. Mas xargs é a cola que você normalmente usa para esse tipo de propósito. Isso ou find ' -exec feature.

    
por 05.09.2012 / 07:43
0

Como complemento, se você usar um shell compatível com o bash, poderá usar a variável GLOBIGNORE para excluir os resultados da correspondência de padrões. Do homem:

   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.

No seu caso particular:

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

Por favor, note que eu corro esse comando como um sub-shell (usando parênteses) para não alterar a variável de ambiente GLOBIGNORE do meu shell interativo.

    
por 18.12.2015 / 21:27
0

Se você não tiver um subdiretório

ls !(*.pdf|*.txt)

também deve funcionar!

Mas

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

é o caminho comum.

    
por 13.04.2018 / 14:39

Tags