Wie funktioniert dieser Befehl find mit "find ... -exec sh -c '...' sh {} +"?

8

@StephaneChazelas hat die folgende Lösung für diese Fragen und Antworten veröffentlicht: Probleme beim Verwenden von "find -exec {} +" .

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

Was genau ist hier los? Was macht der letzte konkret sh {}? Es scheint, als ob es nur dazu da ist, den -execBefehl von find zu befrieden, damit er etwas zu tun hat, einen NOOP.

Ich könnte es genauso gut echo {}dort platzieren und es scheint gut zu funktionieren.

slm
quelle

Antworten:

9

Die Syntax lautet:

find ... -exec cmd {} +

findfindet eine Reihe von Dateien basierend auf den Kriterien in ...und wird cmdmit dieser Liste von Dateipfaden als Argumente ausgeführt, so viele wie möglich, ohne die Begrenzung der Größe der Argumente für einen Befehl zu überschreiten.

Bei Bedarf kann die Liste der Dateien aufgeteilt und cmdmehrmals aufgerufen werden . Zum Beispiel kann es dazu führen, dass Folgendes aufgerufen wird:

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

Eine Einschränkung dabei ist, dass {}es zuletzt sein muss. Sie können zum Beispiel nicht schreiben:

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

wie du könntest mit ';'statt '+'.

Du kannst schreiben:

find ... -exec echo foo {} +

aber nicht:

find ... -exec echo {} foo +

Wenn Sie also cmdnach der Liste der Dateien einige zusätzliche Argumente hinzufügen müssen, müssen Sie eine Shell aufrufen. (Andere Gründe, warum Sie eine Shell aufrufen müssen, sind, wann immer Sie eine Shell-Funktion wie Umleitungen, Pipes, einige Zeichenfolgenerweiterungen verwenden müssen ...)

In sh -c 'inline-script' x a b c, für inline-script, $0ist x, $1ist a, $2ist b... so "$@"ist die Liste dieser 3 Argumente: a, b und c. Also in:

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

Für den Inline - Skript , $0(die zum Beispiel verwendet, wenn Fehlermeldungen angezeigt wird ) auf find-shund "$@"ist die Liste der Dateien (was finderweitert {}wird).

Mit dem execspeziellen eingebauten Shell:

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

Wir weisen die Shell an, keinen zusätzlichen Prozess zum Ausführen zu verzweigen cmd, sondern ihn im selben Prozess auszuführen (indem der laufende Shell-Prozess durch diesen Befehl ersetzt wird). Einige Granaten wie bash, zshund einige Implementierungen kshtun implizit für den letzten Befehl in einem Skript.

Stéphane Chazelas
quelle
Könnten Sie dort eine Subshell anstelle von exec verwenden? -exec sh -c '(cmd1; cmd2;)' find-sh {} +?
slm
Wenn ich Sie also richtig verstehe, find-sh {}sind das Argumente für den Befehl sh -c '...', richtig?
slm
@slm, findruft /bin/shals Argumente auf ("sh", "-c", "...", "find-sh", "./file1", "./file2"...). And inside ... , that maps (the shells maps that) to $ 0` ist "find-sh", und die Positionsparameter ( $1, $2... die man sagen könnte, sind die Argumente für das Inline-Skript ) sind ./file1, ./file2.
Stéphane Chazelas