web-dev-qa-db-fra.com

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

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 semble qu'il n'imprime que .txt des dossiers. Qu'est-ce que je fais mal?

Remarque: en utilisant MINGW (Git Bash)

77
jakub.g
trouver . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt"

est l'abréviation de:

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

Autrement dit, car aucun prédicat action n'est spécifié (uniquement conditions), une action -print Est implicitement ajoutée pour les fichiers qui correspondent aux conditions.

(et, soit dit en passant, cela imprimerait des fichiers .js non réguliers (le -type f ne s'applique qu'aux fichiers .htm)).

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 -une -nom "* .htm *" \) -o \ 
\( -name "* .js *" \) -o \ 
\( -nom "* .txt" -une -exec sh -c 'echo "$ 0"' {} \; \)

Pour find (comme dans de nombreuses langues), ET (-a; Implicite en cas d'omission) a priorité sur OU (-o), et l'ajout d'un prédicat d'action explicite (ici -exec) annule l'action implicite -print vue au dessus de. 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'exécuter un sh par fichier.

105
Stéphane Chazelas

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 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
29
ctrl-alt-delor