Wie führe ich mit find mehrere Befehle aus?

57

Ich versuche, mehrere Befehle für Dinge auszuführen, die ich gefunden habe. Wie kann ich das erreichen?

find . -exec cmd1; cmd2

scheint nicht zu funktionieren; Stattdessen wird cmd2 ausgeführt, nachdem cmd1 für jede Datei ausgeführt wurde.

Tamara Wijsman
quelle

Antworten:

40

In dieser Demonstration werde ich sh -c 'echo first; false'(oder true) für die erste verwenden -exec. Das gibt etwas aus und hat auch den ausgewählten Exit-Code-Effekt. Dann echo secondwird für die zweite verwendet. Angenommen, im aktuellen Verzeichnis befindet sich eine Datei.

$ find . -type f -exec sh -c 'echo first; false' \; -exec echo second \;
first
$ find . -type f -exec sh -c 'echo first; true' \; -exec echo second \;
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second

Ein echter Befehl dieser Art würde so aussehen:

find . -type f \( -exec command1 \; -false -o -exec command2 \; \)

Im zweiten Satz gruppieren die -execgeschützten Klammern die beiden Klauseln. Das -falsedazwischenliegende erzwingt den Testzustand auf "false" und -obewirkt, dass der nächste Ausdruck (der zweite -exec) aufgrund von "false" ausgewertet wird -false.

Von man find:

expr1 expr2
Zwei Ausdrücke in einer Reihe werden verwendet, um mit einem impliziten "und" verbunden zu werden. Ausdruck2 wird nicht ausgewertet, wenn Ausdruck1 falsch ist.

Ausdruck1 -a Ausdruck2
Entspricht Ausdruck1 Ausdruck2.

expr1 -o expr2
Oder; Ausdruck2 wird nicht ausgewertet, wenn Ausdruck1 wahr ist.

Dennis Williamson
quelle
Ah ja, ich habe es vergessen -o.
Ignacio Vazquez-Abrams
32

Wenn es Ihnen egal ist, ob cmd1 die Ausführung von cmd2 aufgrund des Fehlercodes verhindern kann 0:

find . -exec cmd1 \; -exec cmd2 \;

Die einzige zuverlässige Möglichkeit, beide Befehle immer ausführen zu lassen, besteht darin find, eine Shell aufzurufen, die die Befehle anschließend nacheinander ausführt:

find . -exec bash -c 'cmd1; cmd2' filedumper {} \;
Ignacio Vazquez-Abrams
quelle
2

Wenn es Ihnen nichts ausmacht, ein Skript zu erstellen, das cmd1 und cmd2 ausführt, dann ist es nur Folgendes:

find . -exec myscript {} \;

oder

find . -exec myscript {} +

Verwenden \; oder + abhängig davon, ob myscript mehr als eine Datei gleichzeitig verarbeiten kann (wird haarig, wenn in Dateinamen Leerzeichen usw. enthalten sind).

Nach meiner Erfahrung hat es sich fast immer gelohnt, in ein Drehbuch zu schreiben, was Sie getan haben. Wenn Sie es einmal tun müssen, müssen Sie es erneut tun.

Ein guter Trick ist jedoch, den Fund in das Skript einzufügen:

if [ $# -gt 0 ]; then
    for each; do
        touch $each
    done
else
    find . -exec $0 {} +
fi

Dann arbeitet myscript mit allen Dateien, die Sie als Argumente angeben, damit es funktioniert. Wenn Sie jedoch keine Argumente angeben, wird find aus dem aktuellen Verzeichnis ausgeführt und die gefundenen Dateien aufgerufen. Dies umgeht die Tatsache, dass find -exec keine Shell-Funktionen aufrufen kann, die Sie in Ihrem Skript definiert haben.

mza
quelle
0

Ich habe beide vorherigen Lösungen ohne viel Glück ausprobiert. Dieser hat für mich gut funktioniert:

$ for i in `find . -exec echo {} \;`; do cmd1 $i; cmd2 $i; done
user9869932
quelle
Dies funktioniert nicht, wenn die Liste der Dateien zu groß ist.
Alex
-3

try Befehl:

sudo find -name "*[!0-9][1-9].txt" -exec chmod 744 * {} \; -a -exec ls -l {} \; | sort | parallel ls -l
Saptak Das
quelle
4
Eh, das ist keine gute Idee. Das *im -execTeil wird auf alle Dateien im aktuellen Verzeichnis erweitert. Besonders beim Laufen als sudo.
Slhck