find -exec + vs find | xargs: lequel choisir?

32

Je comprends que le -execpeut prendre une +option pour imiter le comportement de xargs. Y a-t-il une situation où vous préféreriez une forme à l'autre?

Personnellement, j'ai tendance à préférer la première forme, ne serait-ce que pour éviter d'utiliser un tuyau. Je figure sûrement les développeurs defind doivent avoir fait les optimisations appropriées. Ai-je raison?

Rahmu
la source

Réponses:

21

Vous voudrez peut-être enchaîner les appels pour trouver (une fois, lorsque vous avez appris, qu'il est possible, ce qui pourrait être le cas aujourd'hui). Ceci n’est bien entendu possible que tant que vous restez en recherche. Une fois que vous dirigez votre recherche vers xargs, c'est hors de portée.

Petit exemple, deux fichiers a.lst et b.lst:

cat a.lst
fuddel.sh
fiddel.sh

cat b.lst
fuddel.sh

Aucune astuce ici - simplement le fait que les deux contiennent "fuddel" mais un seul contient "fiddel".

Supposons que nous ne le savions pas. Nous recherchons un fichier qui correspond à 2 conditions:

find -exec grep -q fuddel {} ";" -exec grep -q fiddel {} ";" -ls
192097    4 -rw-r--r--   1 stefan   stefan         20 Jun 27 17:05 ./a.lst

Eh bien, vous connaissez peut-être la syntaxe permettant à grep ou à un autre programme de transmettre les deux chaînes en tant que condition, mais ce n'est pas la question. Tous les programmes qui peuvent renvoyer true ou false, avec un fichier comme argument, peuvent être utilisés ici - grep n'était qu'un exemple populaire.

Et notez que vous pouvez suivre find -exec avec d'autres commandes find, telles que -ls ou -delete ou quelque chose de similaire. Notez que supprimer non seulement rm (supprime les fichiers), mais également rmdir (supprime les répertoires).

Une telle chaîne est lue comme une combinaison ET de commandes, tant que cela n'est pas spécifié (à savoir avec un -orcommutateur (et des parenthèses (qui doivent être masquées))).

Donc, vous ne quittez pas la chaîne de recherche, ce qui est très pratique. Je ne vois aucun avantage à utiliser -xargs, car vous devez faire preuve de prudence lors de la transmission des fichiers, ce qui n'est pas forcément une tâche inutile - il gère automatiquement la transmission de chaque fichier en tant qu'argument unique.

Si vous pensez avoir besoin d'un masque pour les accolades , n'hésitez pas à consulter ma question qui demande des preuves. Mon affirmation est la suivante: vous ne le faites pas.

Utilisateur inconnu
la source
3
Cet article m'a ouvert les yeux sur une nouvelle façon d'utiliser find. Merci beaucoup!
Rahmu
1
"Je ne vois aucun avantage à utiliser -xargs". Comment -execfaire xargs -P4pour que trois des quatre cœurs ne restent pas inactifs?
Damian Yerrick
1
@ DamianYerrick: Terminez la commande -exec pas dans ";" mais avec un + (/ signe plus).
utilisateur inconnu
25

Sécuriser les noms de fichiers à xargsnécessite que votre option soit prise en charge et que vous finddisposiez de l’ -print0option xargscorrespondante pour la lire ( --nullou -0). Sinon, les noms de fichiers contenant des caractères non imprimables, des barres obliques inverses, des guillemets ou des espaces peuvent provoquer un comportement inattendu. Par contre, il find -exec {} +est conforme à la findspécification POSIX , il est donc portable et il est à peu près aussi sûr find -print0 | xargs -0et certainement plus sûr que find | xargs. Je recommanderais de ne jamais faire find | xargssans -print0.

jw013
la source
6
find … -exec … {} +OpenBSD est une exception notable à la portabilité , qui n’a acquis cette fonctionnalité qu’avec la version 5.1 publiée en 2012. Tous les BSD ont -print0depuis plusieurs années, même OpenBSD (bien qu’il ait résisté à cette fonctionnalité pendant un certain temps également). Solaris, quant à lui, reste fidèle aux fonctionnalités POSIX, donc vous obtenez -exec +et non -print0.
Gilles 'SO- arrête d'être méchant'
-print0C'est une douleur et bien que vous puissiez dire que ce xargs --delimiter "\n"n'est pas équivalent, je n'ai jamais utilisé le premier après avoir découvert le dernier.
Sridhar Sarnobat le
3
Je ne vois pas comment -0c'est plus pénible que --delimiter "\n".
jw013
2
De plus -0, GNU xargsdoit -réviter d’exécuter la commande s’il n’ya pas d’entrée.
Stéphane Chazelas
2
Un autre problème | xargs -r0 cmdest que cmdle stdin est affecté (en fonction de la xargsmise en œuvre, de son fonctionnement /dev/nullou de la conduite).
Stéphane Chazelas
10

Si vous utilisez le -exec ... ;formulaire (en vous rappelant d'échapper au point-virgule), vous exécutez la commande une fois par nom de fichier. Si vous utilisez -print0 | xargs -0, vous exécutez plusieurs commandes par nom de fichier. Vous devez absolument utiliser le -exec +formulaire, qui place plusieurs fichiers dans une seule ligne de commande et est beaucoup plus rapide lorsqu'un grand nombre de fichiers est impliqué.

Un gros plus de l'utilisation xargsest la possibilité d'exécuter plusieurs commandes en parallèle à l'aide xargs -P. Sur les systèmes multicœurs, cela peut permettre de gagner beaucoup de temps.

Alexios
la source
6
Vous vouliez dire -Pau lieu de -p. N'oubliez pas que ce xargs -Pn'est pas dans le standard POSIX find -exec {} +, ce qui est important si vous optez pour la portabilité.
jw013
@Alexios Vous n'avez pas à échapper au signe plus, car il n'a pas de signification particulière pour le shell: find /tmp/ -exec ls "{}" +fonctionne très bien.
daniel kullmann
1
Corrent, bien sûr. Je me suis tout échappé -execdepuis si longtemps (je suis masochiste, je n'utilise même pas de guillemets pour m'échapper {}, je tape toujours \{\}; ne demandez pas), on dirait que tout doit être échappé maintenant.
Alexios
1
@Alexios: Si vous trouvez un exemple (sauf d'être un masochiste) dans lequel le masquage des accolades est utile, veuillez le fournir en réponse à ma question ici . Je n'ai jamais vu d'exemple où find /tmp/ -exec ls {} +cela ne fonctionnerait pas.
utilisateur inconnu
1
Pour moi, ceci est une mémoire musculaire formée à l'époque de SunOS 4. Comme je le fais depuis des années, je n'ai absolument pas remarqué quand j'ai bashcommencé à accepter les orthèses textuellement. Je suis à peu près sûr qu'au moins un des vieux coquillages que j'ai utilisés a jeté une crise si les bretelles n'étaient pas échappées.
Alexios
8

En ce qui concerne les performances, j’ai pensé que ce -exec … +serait tout simplement préférable, car c’est un outil unique qui fait tout le travail, mais une partie de la documentation de GNU findutil indique que cela -exec … +pourrait être moins efficace dans certains cas:

[trouver avec -exec … +] peut être moins efficace que certaines utilisations de xargs; Par exemple, xargspermet de créer de nouvelles lignes de commande alors que la commande précédente est encore en cours d'exécution et de spécifier un certain nombre de commandes à exécuter en parallèle. Cependant, cette find ... -exec ... +construction présente l’avantage d’une large portabilité. GNU findutils ne supportait pas ' -exec ... +' jusqu'à la version 4.2.12 [janvier 2005] ; une des raisons en est qu’il y avait déjà une -print0action dans tous les cas.

Je ne savais pas trop ce que cela voulait dire, alors j'ai demandé dans le chat où Derobert l' expliquait ainsi:

findpourrait probablement continuer à rechercher le prochain lot de fichiers en cours d’ -exec … +exécution, mais ce n’est pas le cas.
find … | xargs …fait, car alors la recherche est un processus différent, et elle continue à s'exécuter jusqu'à ce que le tampon de canalisation se remplisse

(Formatage par moi.)

Donc, il y a ça. Mais si les performances importent vraiment, vous devrez procéder à des analyses comparatives réalistes ou plutôt vous demander même si vous souhaitez même utiliser shell pour de tels cas.

Ici, sur ce site, je pense qu'il est préférable de conseiller aux gens d'utiliser le -exec … +formulaire chaque fois que possible, simplement parce que c'est plus simple et pour les raisons mentionnées dans les autres réponses ici (par exemple, gérer des noms de fichiers étranges sans trop réfléchir).

phk
la source