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
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
.
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
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
.
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' *
find /path/to/directory '!' -name '*.pdf' '!' -name '*.txt'
Isto é equivalente ao comando com o operador OR, devido às leis de De Morgan .
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.
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.
Se você não tiver um subdiretório
ls !(*.pdf|*.txt)
também deve funcionar!
Mas
ls -I "*.pdf" -I "*.txt"
é o caminho comum.