web-dev-qa-db-fra.com

Comment exécuter plusieurs commandes lors de l'utilisation de find?

J'essaie d'exécuter plusieurs commandes sur des choses que j'ai trouvées. Comment puis-je y parvenir?

find . -exec cmd1; cmd2

ne semble pas fonctionner; à la place, il exécute cmd2 après l'exécution de cmd1 sur chaque fichier.

55
Tamara Wijsman

Dans cette démonstration, je vais utiliser sh -c 'echo first; false' (ou true) pour le premier -exec. Cela donnera une sortie et aura également l'effet du code de sortie sélectionné. Alors echo second sera utilisé pour le second. Supposons qu'il y a un fichier dans le répertoire actuel.

$ find . -type f -exec sh -c 'echo first; false' \; -exec echo second \;
first
$ find . -type f -exec sh -c 'echo first; true' \; -exec echo second \;
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second

Une vraie commande de ce type ressemblerait à ceci:

find . -type f \( -exec command1 \; -false -o -exec command2 \; \)

Dans le deuxième ensemble, les parenthèses échappées regroupent les deux clauses -exec. Le -false entre eux force l'état de test à "false" et le -o provoque l'évaluation de l'expression suivante (le second -exec) à cause du -false.

De man find:

expr1 expr2
Deux expressions consécutives sont associées à un "et" implicite; expr2 n'est pas évalué si expr1 est faux.

expr1 -a expr2
Identique à expr1 expr2.

expr1 -o expr2
Ou; expr2 n'est pas évalué si expr1 est vrai.

40
Dennis Williamson

Si vous ne voulez pas que cmd1 puisse empêcher l'exécution de cmd2 à cause du code d'erreur 0:

find . -exec cmd1 \; -exec cmd2 \;

Le seul moyen fiable d’exécuter toujours les deux commandes consiste à faire en sorte que find appelle un shell qui exécutera ensuite les commandes dans l’ordre:

find . -exec bash -c 'cmd1; cmd2' filedumper {} \;
32

Si cela ne vous dérange pas de faire un script qui fait cmd1 et cmd2, alors c'est juste ceci:

find . -exec myscript {} \;

ou

find . -exec myscript {} +

Utilisation \; ou + selon que myscript peut gérer plus d'un fichier à la fois (devient poilu s'il y a des espaces dans les noms de fichiers, etc.).

D'après mon expérience, mettre ce que vous faisiez dans un script en a presque toujours valu la peine. Si vous devez le faire une fois, vous devrez le refaire.

Mais une astuce consiste à placer la recherche à l'intérieur du script:

if [ $# -gt 0 ]; then
    for each; do
        touch $each
    done
else
    find . -exec $0 {} +
fi

Ensuite, myscript fonctionne sur tous les fichiers que vous donnez comme arguments, mais si vous ne lui en donnez pas, il lance find depuis le répertoire en cours, puis s’appelle lui-même sur les fichiers trouvés. Cela contourne le fait que find -exec ne peut pas appeler les fonctions Shell que vous avez définies dans votre script.

2
mza

J'ai essayé les deux solutions précédentes sans trop de chance. Celui-ci a bien fonctionné pour moi:

$ for i in `find . -exec echo {} \;`; do cmd1 $i; cmd2 $i; done
0
user1183098