`find` com múltiplos` -name` e `-exec` executam apenas as últimas correspondências de` -name`

74

Quando estou usando

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"

encontra todos os tipos de arquivo. Mas quando eu adiciono -execno final:

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' {} \;

parece que apenas imprime .txtarquivos. O que estou fazendo errado?

Nota: usando MINGW (Git Bash)

jakub.g
fonte
Dica: o primeiro comando também imprimirá diretórios cujos nomes correspondem *.js*ou *.txt.
Wildcard

Respostas:

99
encontrar . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt"

é a abreviação de:

encontrar . \ (\ ( -type f -a -name "* .htm *" \) -o \
          \ ( -name "* .js *" \) -o \
          \ ( -name "* .txt" \) \
       \) -uma impressão

Ou seja, como nenhum predicado de ação é especificado (apenas condições ), uma -printação é incluída implicitamente para os arquivos que correspondem às condições.

(e, a propósito, isso imprimiria .jsarquivos não regulares (o -type fúnico se aplica a .htmarquivos)).

Enquanto:

encontrar . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt" \
  -exec sh -c 'echo "$ 0"' {} \;

é a abreviação de:

encontrar . \ ( -tipo f -a -name "* .htm *" \) -o \
       \ ( -name "* .js *" \) -o \
       \ ( -name "* .txt" -a -exec sh -c 'echo "$ 0"' {} \; \)

Para find(como em muitos idiomas), AND ( -a; implícito quando omitido) tem precedência sobre OR ( -o), e adicionar um predicado de ação explícito (aqui -exec) cancela a -printação implícita vista acima. Aqui você quer:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) \
  -exec sh -c 'echo "$0"' {} \;

Ou:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c '
   for i do
     echo "$i"
   done' sh {} +

Para evitar a execução de um shpor arquivo.

Stéphane Chazelas
fonte
Em alguns desses usos do sh -c, você precisa adicionar o argumento zeroth para o sh (embora em outros você já o tenha incluído).
James Youngman
11
Essa é uma ótima resposta!
Marinos Um
30

São os colchetes implícitos. Adicione colchetes explícitos.\( \)

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c 'echo "$0"' {} \;

ou usando xargs (eu gosto de xargs, acho mais fácil, mas aparentemente não tão portátil).

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -print0 | xargs -0 -n1 echo
ctrl-alt-delor
fonte