find -exec + vs find | xargs: welches soll man wählen?

32

Ich verstehe, dass -execes eine +Option geben kann, um das Verhalten von nachzuahmen xargs. Gibt es eine Situation, in der Sie eine Form der anderen vorziehen würden?

Ich persönlich bevorzuge eher die erste Form, schon gar nicht die Pfeife. Ich findnehme an, die Entwickler von müssen die entsprechenden Optimierungen vorgenommen haben. Hab ich recht?

rahmu
quelle

Antworten:

21

Vielleicht möchten Sie Anrufe verketten, um zu finden (einmal, als Sie erfuhren, dass es möglich ist, was heute sein könnte). Dies ist natürlich nur möglich, solange Sie in find bleiben. Sobald Sie eine Pipe an xargs gesendet haben, ist dies nicht mehr möglich.

Kleines Beispiel, zwei Dateien a.lst und b.lst:

cat a.lst
fuddel.sh
fiddel.sh

cat b.lst
fuddel.sh

Kein Trick hier - einfach die Tatsache, dass beide "Fuddel" enthalten, aber nur eine "Fiddel" enthält.

Angenommen, wir wüssten das nicht. Wir suchen eine Datei, die 2 Bedingungen entspricht:

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

Nun, vielleicht kennen Sie die Syntax für grep oder ein anderes Programm, um beide Zeichenfolgen als Bedingung zu übergeben, aber das ist nicht der Punkt. Jedes Programm, das true oder false zurückgeben kann, wenn eine Datei als Argument angegeben wird, kann hier verwendet werden - grep war nur ein beliebtes Beispiel.

Beachten Sie, dass Sie find -exec mit anderen Suchbefehlen wie -ls oder -delete oder ähnlichem folgen können . Beachten Sie, dass delete nicht nur rm (Dateien entfernt), sondern auch rmdir (Verzeichnisse entfernt).

Solch eine Kette wird als UND-Verknüpfung von Befehlen gelesen, sofern nichts anderes angegeben ist (nämlich mit einem -orSchalter (und Parens (die maskiert werden müssen)).

Sie verlassen also nicht die Suchkette, was praktisch ist. Ich sehe keinen Vorteil in der Verwendung von -xargs, da Sie beim Übergeben der Dateien vorsichtig sein müssen, was bei find nicht erforderlich ist - es wird automatisch jede Datei als einzelnes Argument für Sie übergeben.

Wenn Sie glauben , Sie findet einige Maskierung benötigen {} Klammern , fühlen sich frei , meine Frage zu besuchen , die nach Beweisen fragt. Meine Behauptung ist: Du nicht.

Benutzer unbekannt
quelle
3
Dieser Beitrag hat meine Augen für eine neue Art der Verwendung geöffnet find. Vielen Dank!
Rahmu
1
"Ich sehe keinen Vorteil in der Verwendung von -xargs". Was ist die -execArt und Weise zu tun , xargs -P4so dass drei von vier Kernen nicht untätig bleiben?
Damian Yerrick
1
@DamianYerrick: Beende den -exec Befehl nicht in ";" aber mit einem + (/ Pluszeichen).
Benutzer unbekannt
25

Das sichere Weiterleiten von Dateinamen an xargserfordert, dass Sie finddie -print0Option unterstützen und xargsüber die entsprechende Option zum Lesen verfügen ( --nulloder -0). Andernfalls können Dateinamen mit nicht druckbaren Zeichen oder umgekehrten Schrägstrichen oder Anführungszeichen oder Leerzeichen im Namen zu unerwartetem Verhalten führen. Andererseits find -exec {} +ist es in der POSIX- findSpezifikation enthalten , ist also portabel und ungefähr so ​​sicher wie find -print0 | xargs -0und definitiv sicherer als find | xargs. Ich würde empfehlen, niemalsfind | xargs ohne auszukommen -print0.

jw013
quelle
6
Eine bemerkenswerte Ausnahme von der Portabilität von find … -exec … {} +OpenBSD ist OpenBSD, das diese Funktion erst mit der Version 5.1, die im Jahr 2012 veröffentlicht wurde, erworben hat -print0. Solaris hingegen hält an POSIX-Funktionen fest, sodass Sie -exec +keine Probleme haben -print0.
Gilles 'SO- hör auf böse zu sein'
-print0ist ein Schmerz und obwohl man argumentieren kann, dass er xargs --delimiter "\n"nicht gleichwertig ist, habe ich den ersteren noch nie benutzt, nachdem ich den letzteren entdeckt habe.
Sridhar Sarnobat
3
Ich verstehe nicht, wie -0schmerzhafter das ist --delimiter "\n".
JW013
2
Neben -0GNU xargsmuss -rAusführen des Befehls vermeiden , wenn es keine Eingabe ist.
Stéphane Chazelas
2
Ein weiteres Problem | xargs -r0 cmdist, dass cmddie stdin betroffen ist (je nach xargsImplementierung ist es /dev/nulloder die Pipe.
Stéphane Chazelas
10

Wenn Sie das -exec ... ;Formular verwenden (daran denken, das Semikolon zu schließen), führen Sie den Befehl einmal pro Dateiname aus. Wenn Sie verwenden -print0 | xargs -0, führen Sie mehrere Befehle pro Dateiname aus. Sie sollten auf jeden Fall das -exec +Formular verwenden, das mehrere Dateien in einer einzigen Befehlszeile enthält und bei einer großen Anzahl von Dateien viel schneller ist.

Ein großes Plus der Verwendung xargsist die Möglichkeit, mehrere Befehle gleichzeitig auszuführen xargs -P. Bei Multi-Core-Systemen kann dies eine enorme Zeitersparnis bedeuten.

Alexios
quelle
6
Du meintest -Pstatt -p. Beachten Sie, dass dies xargs -Pnicht im POSIX-Standard enthalten ist. Dies find -exec {} +ist jedoch wichtig, wenn Sie Portabilität anstreben.
JW013
@Alexios Das Pluszeichen muss nicht umgangen werden, da es für die Shell keine besondere Bedeutung hat: Funktioniert einwandfrei find /tmp/ -exec ls "{}" +.
Daniel Kullmann
1
Natürlich Corrent. Ich bin -execso lange vor allem davongekommen (ich bin ein Masochist, ich benutze nicht einmal Anführungszeichen {}, ich tippe immer \{\}; frage nicht), alles sieht so aus, als müsste es jetzt geflüchtet werden.
Alexios
1
@Alexios: Wenn Sie ein Beispiel finden (außer als Masochist), bei dem das Maskieren der Klammern nützlich ist, geben Sie es bitte als Antwort auf meine Frage hier an - wie gesagt, dieser Hinweis ist veraltet und nur ein Relikt in der Manpage. Ich habe noch nie ein Beispiel gesehen, wo find /tmp/ -exec ls {} +es nicht funktionieren würde.
Benutzer unbekannt
1
Für mich ist dies ein Muskelgedächtnis, das sich in den Tagen von SunOS 4 gebildet hat. Da ich es seit Jahren mache, habe ich es nicht bemerkt, als ich bashanfing, die Zahnspange wörtlich zu akzeptieren. Ich bin mir ziemlich sicher, dass mindestens eine der alten Muscheln, die ich verwendet habe, zischende Anfälle verursacht hat, wenn die Zahnspangen nicht entkommen sind.
Alexios
8

Was die Leistung angeht, dachte ich, das -exec … +wäre einfach besser, weil es ein einziges Tool ist, das die ganze Arbeit erledigt, aber ein Teil der Dokumentation von GNU findutil besagt, dass -exec … +dies in einigen Fällen weniger effizient sein könnte:

[find with -exec … +] kann weniger effizient sein als manche Verwendungen von xargs; Beispielsweise xargskönnen neue Befehlszeilen erstellt werden, während der vorherige Befehl noch ausgeführt wird, und Sie können eine Reihe von Befehlen angeben, die parallel ausgeführt werden sollen. Das find ... -exec ... +Konstrukt hat jedoch den Vorteil einer breiten Portabilität. GNU-Findutils unterstützten ' -exec ... +' erst ab Version 4.2.12 [Januar 2005] ; einer der gründe dafür ist, dass es ohnehin schon die -print0aktion hatte.

Ich war mir nicht ganz sicher, was das zu bedeuten hatte, also fragte ich im Chat, wo derobert es erklärte:

findMöglicherweise könnte die Suche nach dem nächsten Stapel von Dateien fortgesetzt werden, während die ausgeführt -exec … +wird, dies ist jedoch nicht der Fall.
find … | xargs …Dies ist der Fall, da der Suchvorgang dann ein anderer Vorgang ist und so lange ausgeführt wird, bis der Pipe-Puffer voll ist

(Formatierung von mir.)

Das ist es also. Aber wenn es wirklich auf die Leistung ankommt, müsste man ein realistisches Benchmarking durchführen oder sich sogar fragen, ob man in solchen Fällen überhaupt die Shell verwenden möchte.

Hier auf dieser Seite ist es meines Erachtens besser, den Leuten zu raten, das -exec … +Formular zu verwenden, wann immer dies möglich ist, weil es einfacher ist und aus den in den anderen Antworten genannten Gründen (z. B. Umgang mit seltsamen Dateinamen, ohne viel nachzudenken).

phk
quelle