Comment fonctionne cette commande find en utilisant «find… -exec sh -c '…» sh {} + »?

8

@StephaneChazelas a publié la solution suivante à ce Q&R: avoir des problèmes avec "find -exec {} +" .

$ find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +

Que se passe-t-il exactement ici? Plus précisément, que fait le dernier sh {}? Il semble que ce soit juste là pour pacifier la -execcommande de find afin qu'elle ait quelque chose à faire, un NOOP.

Je pourrais tout aussi bien echo {}y mettre et cela semble fonctionner très bien.

slm
la source

Réponses:

9

La syntaxe est:

find ... -exec cmd {} +

findtrouvera un certain nombre de fichiers en fonction des critères dans ...et s'exécutera cmdavec cette liste de chemins de fichiers comme arguments, autant que possible sans dépasser la limite de la taille des arguments d'une commande.

Si nécessaire, il peut diviser la liste des fichiers et appeler cmdplusieurs fois. Par exemple, il peut finir par appeler:

cmd ./file1 ./file2 ... ./file3000
cmd ./file3001 ./file3002 ... ./file4321

Une limitation à cela est que cela {}doit être le dernier. Vous ne pouvez pas par exemple écrire:

find ... -exec cmd {} other args +

comme vous pourriez avec ';'au lieu de '+'.

Tu peux écrire:

find ... -exec echo foo {} +

mais non:

find ... -exec echo {} foo +

Donc, si vous avez besoin d'ajouter des arguments supplémentaires cmdaprès la liste des fichiers, vous devez recourir à l'appel d'un shell. (D'autres raisons pour lesquelles vous auriez besoin d'appeler un shell seraient chaque fois que vous avez besoin d'utiliser une fonctionnalité de shell comme les redirections, les tuyaux, certaines extensions de chaîne ....)

Dans sh -c 'inline-script' x a b c, pour le inline-script, $0est x, $1est a, $2est b... ainsi que "$@"la liste de ces 3 arguments: a, b et c. Donc dans:

find ... -exec sh -c 'cmd "$@" other arg' find-sh {} +

Pour le script en ligne , $0(qui est utilisé par exemple lors de l'affichage de messages d'erreur) est défini sur find-shet "$@"est la liste des fichiers (ce qui se finddéveloppe {}).

En utilisant le execmodule intégré spécial du shell:

find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +

Nous disons au shell de ne pas lancer un processus supplémentaire à exécuter cmd, mais plutôt de l'exécuter dans le même processus (en remplaçant le processus shell en cours d'exécution par cette commande). Certains shells aiment bash, zshet certaines implémentations de le kshfont implicitement pour la dernière commande d'un script.

Stéphane Chazelas
la source
Pourriez-vous utiliser un sous-shell au lieu d'exécuter là-bas? -exec sh -c '(cmd1; cmd2;)' find-sh {} +?
slm
Donc, si je vous comprends bien, ce find-sh {}sont des arguments pour la commande sh -c '...', non?
slm
@slm, findappellera /bin/shavec comme arguments ("sh", "-c", "...", "find-sh", "./file1", "./file2"...). And inside ... , that maps (the shells maps that) to $ 0` être "find-sh", et les paramètres de position ( $1, $2... que vous pourriez dire que les arguments du script en ligne ) étant ./file1, ./file2.
Stéphane Chazelas