Wann wird `finden. -exec BEFEHL {} + `BEFEHL mehrmals ausführen?

8

Wenn ich mache

find . -exec echo {} +

Es werden alle Pfade in einer Zeile gedruckt, dh der Befehl echowird nur einmal ausgeführt.

Aber nach man find,

-exec command {} +
    ... the number of invocations of the command will 
be much  less  than  the  number  of matched files. ...

Es scheint, dass der Befehl unter bestimmten Umständen mehrmals ausgeführt wird. Habe ich recht? Bitte veranschaulichen Sie.

gefrorene Flamme
quelle

Antworten:

7

POSIX definiert find -exec Dienstprogrammname [Argument ...] {} + als:

Das Ende des primären Ausdrucks wird durch ein <semicolon> oder ein <plus-sign> unterbrochen. Nur ein <plus-sign>, das unmittelbar auf ein Argument folgt, das nur die beiden Zeichen "{}" enthält, darf das Ende des primären Ausdrucks markieren. Andere Verwendungen des <plus-sign> werden nicht als besonders behandelt. Wenn der primäre Ausdruck durch ein <Semikolon> unterbrochen wird , wird der Dienstprogrammname für jeden Pfadnamen einmal aufgerufen, und der primäre Ausdruck wird als wahr ausgewertet, wenn das Dienstprogramm einen Nullwert als Beendigungsstatus zurückgibt. Ein Dienstprogrammname oder ein Argument, das nur die beiden Zeichen "{}" enthält, wird durch den aktuellen Pfadnamen ersetzt. Wenn ein Dienstprogrammname oder ein ArgumentDie Zeichenfolge enthält die beiden Zeichen "{}", aber nicht nur die beiden Zeichen "{}". Es ist implementierungsdefiniert, ob find diese beiden Zeichen ersetzt oder die Zeichenfolge unverändert verwendet.

Wenn der primäre Ausdruck durch ein <plus-sign> unterbrochen wird, wird der primäre immer als wahr ausgewertet, und die Pfadnamen, für die der primäre Ausdruck ausgewertet wird, werden zu Mengen zusammengefasst. Das Dienstprogramm Utility_name wird für jeden Satz aggregierter Pfadnamen einmal aufgerufen. Jeder Aufruf wird beginnen , nachdem der letzte Pfad in dem Satz zusammengefasst wird, und wird vor den abgeschlossen seinem Fund Dienstprogramm Ausfahrten und vor dem ersten Pfad in dem nächsten Satz (falls vorhanden) ist für diesen primären aggregiert, aber es ist anders , nicht spezifiziert , ob der Aufruf tritt vor, während oder nach den Bewertungen anderer Vorwahlen auf. Wenn ein Aufruf einen Wert ungleich Null als Exit-Status zurückgibt, wird die Suche ausgeführt Das Dienstprogramm muss einen Exit-Status ungleich Null zurückgeben. Ein Argument, das nur die beiden Zeichen "{}" enthält, wird durch die Menge der aggregierten Pfadnamen ersetzt, wobei jeder Pfadname als separates Argument in der gleichen Reihenfolge an das aufgerufene Dienstprogramm übergeben wird, in der er aggregiert wurde. Die Größe eines Satzes von zwei oder mehr Pfadnamen muss so begrenzt sein, dass die Ausführung des Dienstprogramms nicht dazu führt, dass das {ARG_MAX} -Limit des Systems überschritten wird . Wenn mehr als ein Argument mit den beiden Zeichen "{}" vorhanden ist, ist das Verhalten nicht angegeben.

Wenn der gefundene Längensatz des Dateinamens das System überschreitet ARG_MAX, wird der Befehl ausgeführt.

Sie können erhalten ARG_MAXmit getconf :

$ getconf ARG_MAX
2097152

Bei einigen Systemen kann der tatsächliche Wert von ARG_MAXunterschiedlich sein. Weitere Informationen finden Sie hier .

cuonglm
quelle
Ich habe ein Experiment durchgeführt find / -exec echo | wcund das Verhältnis zwischen Zeichenanzahl und Zeilenanzahl gemessen. Ich habe festgestellt, dass die maximale Befehlszeilenlänge, die von verwendet findwird, erheblich kleiner als die theoretische POSIX-Grenze ist und viel näher an der Size of command buffer we are actually usingZeile in der Ausgabe von liegt xargs --show-limits. Dies gilt für Linux und möglicherweise für die Mac OS-Implementierung von find, obwohl xargsder Wert in Mac OS nicht gedruckt wird. Irgendeine Idee, warum das passiert?
pqnet
--show-limitswird von POSIX nicht angegeben, die Mac OS-Implementierung von xargsunterstützt es nicht. find / -exec echo | wcwird nicht funktionieren. Denken Sie daran, dass ARG_MAXRückgabebytes. Und es ist die maximale Länge der Argumente für die exec(3)Funktionen.
Cuonglm
Ich weiß, dass --show-limitses sich nicht um POSIX handelt, obwohl dies nicht die maximale Argumentlänge ist, die von verwendet wird findund die einen kleineren Wert verwendet. Ich verstehe nicht, warum Sie sagen, dass find / -exec echo | wcdas nicht funktioniert: Meiner Meinung nach ist es eine gute Möglichkeit, den tatsächlichen Wert abzuschätzen (und nach dem, was ich sehen kann, besser als zu verwenden getconf ARG_MAX). Außerdem besteht mein Dateisystem meistens aus allen ASCII-Zeichen, sodass die Anzahl der Zeichen ungefähr der Anzahl der Bytes entspricht.
pqnet
@pqnet: benutze find / -exec sh -c 'echo $@ | wc -c' _ {} +isntead.
Cuonglm
Entschuldigung, ich habe es falsch geschrieben, ich habe es tatsächlich benutztfind / -exec echo {} + | wc -lc
pqnet
7

Es gibt eine maximale Länge der Argumentliste für einen neuen Prozess im POSIX-System. findteilt die Ausführung auf, wenn die Dateipfade länger sind. Um das Limit unter Linux zu sehen, verwenden Sie xargs --show-limits(funktioniert nicht unter Mac OS, wenn jemand eine bessere Alternative kennt, kommentieren Sie bitte hier)

edit: direkt aus Gnoucs Antwort gestohlen, der POSIX-Weg, um die maximale Länge der Argumentliste zu erhalten, ist getconf ARG_MAX. Ich habe jedoch ein Experiment auf meinem Mac OS-Computer durchgeführt, und es sieht so findaus, als würde etwas mehr als die Hälfte dieser Zahl verwendet. Dies steht im Einklang mit der Tatsache, dass auf dem System, auf dem es funktioniert, angegeben xargs --show-limitswird, dass nicht die maximale Argumentlänge verwendet wird (auch in diesem Fall wird etwa die Hälfte dieser Zahl verwendet), ich konnte jedoch keine Erklärung finden dafür.

edit 2: Es scheint, dass die einzige zuverlässige Methode, um zu bestimmen, wie viele Parameter findfür jeden Aufruf zusammenhalten, das Experimentieren ist, beispielsweise durch Ausführen

find / -exec echo {} + | wc -cl

Da die Ausgabe von findfür jeden echoAufruf eine Zeile enthält , können sie mit gezählt werden wc -l. Die Gesamtzahl der Bytes echoist die Ausgabe von wc -cstattdessen. Wenn Sie eine durch die andere teilen, erhalten Sie die durchschnittliche Anzahl von Bytes in den Parametern für jeden Befehlsaufruf (wenn auch aufgrund der Rundung ein etwas niedrigerer Wert, ungefähr die Hälfte der durchschnittlichen Länge eines Pfads in Ihrem System).

pqnet
quelle
xargsverwendet nicht die volle maximale Argumentlänge, da viele Programme einige zusätzliche Argumente voranstellen und die Argumente dann an andere Programme übergeben. Wenn xargsdie Argumente bis zum absoluten Maximum gefüllt werden, werden solche Programme unterbrochen, da für diese zusätzlichen Argumente kein Platz mehr wäre.
hvd
@hvd macht Sinn. Aber gibt es dann eine POSIX-Methode, um zu wissen, wie viel Puffer von xargsoder verwendet wird find?
pqnet
Sie können es mit einer sehr langen Liste von Argumenten ausführen, yes . | xargs | head -n 1 | wc -cindem Sie bestimmen, wie viele Argumente beim ersten Aufruf übergeben wurden (so etwas wie ) und diese mit der Ausgabe von vergleichen getconf ARG_MAX. Aber wenn ich es tatsächlich auf meinem System versuche, bekomme ich einen Unterschied, der so groß ist, dass es so aussieht, als ob mehr dahinter steckt, als mir bewusst ist.
hvd
Also läuft