`find` avec plusieurs` -name` et `-exec` n'exécute que les dernières correspondances de` -name`

74

Quand j'utilise

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

il trouve tous les types de fichiers. Mais quand j'ajoute -execà la fin:

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

il semblerait que seuls les .txtfichiers soient imprimés . Qu'est-ce que je fais mal?

Remarque: en utilisant MINGW (Git Bash)

jakub.g
la source
Astuce: la première commande imprimera également les répertoires dont les noms correspondent *.js*ou *.txt.
Wildcard

Réponses:

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

est l'abréviation de:

trouver . \ (\ ( -type f -a -name "* .htm *" \) -o \
          \ ( -name "* .js *" \) -o \
          \ ( -name "* .txt" \) \
       \) -un imprimé

Autrement dit, aucun prédicat d' action n'étant spécifié (uniquement des conditions ), une -printaction est implicitement ajoutée pour les fichiers correspondant aux conditions.

(et, en passant, cela imprimerait des .jsfichiers non réguliers (la -type fseule s'applique aux .htmfichiers)).

Tandis que:

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

est l'abréviation de:

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

Car find(comme dans de nombreuses langues), AND ( -a; implicite lorsque omis) a la priorité sur OR ( -o) et l’ajout d’un prédicat d’action explicite (ici -exec) annule l’ -printaction implicite vue ci-dessus. Ici, vous voulez:

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 {} +

Pour éviter d'en exécuter un shpar fichier.

Stéphane Chazelas
la source
Dans certaines de ces utilisations sh -c, vous devez ajouter l'argument zeroth pour sh (bien que vous l'ayez déjà inclus dans d'autres).
James Youngman
1
C'est une excellente réponse!
Marinos Un
30

Ce sont les parenthèses implicites. Ajoutez des crochets explicites.\( \)

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

ou en utilisant xargs (j'aime bien xargs je le trouve plus facile, mais apparemment pas aussi portable).

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