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


57

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.

Réponses:


40

Dans cette démonstration, je vais utiliser sh -c 'echo first; false'(ou true) pour la première -exec. Cela donnera une sortie et aura également l'effet du code de sortie sélectionné. Ensuite, echo secondsera 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 -execclauses. L ' -falseentre eux force l' état de test à "faux" et -oprovoque l ' -execévaluation de l' expression suivante (la seconde ) à cause de la -false.

De man find:

expr1 expr2
Deux expressions dans une ligne sont prises pour être jointes avec 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.


Ah oui, j'ai oublié -o.
Ignacio Vazquez-Abrams le

32

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 à findappeler un shell qui les exécutera ensuite en séquence:

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

2

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 faire à nouveau.

Mais une astuce consiste à insérer la découverte dans le 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 de shell que vous avez définies dans votre script.


0

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

Cela ne fonctionnera pas si la liste de fichiers est trop longue.
Alex

-3

essayez la commande:

sudo find -name "*[!0-9][1-9].txt" -exec chmod 744 * {} \; -a -exec ls -l {} \; | sort | parallel ls -l

4
Eh, ce n'est pas une bonne idée. Le *dans la -execpartie sera étendu à tous les fichiers du répertoire actuel. Surtout en tant que sudo.
Slhck
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.