Dies ist eine Einschränkung von find
. Der POSIX-Standard gibt an, dass der Rückgabestatus find
0 ist, es sei denn, beim Durchlaufen der Verzeichnisse ist ein Fehler aufgetreten. Der Rückgabestatus von ausgeführten Befehlen wird nicht berücksichtigt.
Sie können Befehle veranlassen, ihren Status in eine Datei oder einen Deskriptor zu schreiben:
find_status_file=$(mktemp findstatus)
: >"$find_status_file"
find … -exec sh -c 'trap "echo \$?" EXIT; invalid_command "$0"' {} \;
if [ -s "$find_status_file" ]; then
echo 1>&2 "An error occurred"
fi
rm -f "$find_status_file"
Wie Sie festgestellt haben , besteht eine andere Methode darin, xargs zu verwenden. Der xargs
Befehl verarbeitet immer alle Dateien, gibt jedoch den Status 1 zurück, wenn einer der Befehle einen Status ungleich Null zurückgibt.
find … -print0 | xargs -0 -n1 invalid_command
Eine weitere Methode besteht darin, find
stattdessen rekursives Globbing in der Shell zu vermeiden und zu verwenden: **/
bedeutet eine beliebige Tiefe von Unterverzeichnissen. Dies erfordert Version 4 oder höher von bash. Da macOS bei Version 3.x nicht mehr funktioniert, muss es von einer Port-Sammlung installiert werden. Dient set -e
zum Anhalten des Skripts beim ersten Befehl, der einen Status ungleich Null zurückgibt.
shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done
Beachten Sie, dass dies in Bash 4.0 bis 4.2 funktioniert, jedoch symbolische Verknüpfungen zu Verzeichnissen durchläuft, was normalerweise nicht wünschenswert ist.
Wenn Sie zsh anstelle von bash verwenden, funktioniert das rekursive Globbing ohne Abstriche. Zsh ist standardmäßig unter OSX / macOS verfügbar. In zsh kann man einfach schreiben
set -e
for x in **/*.xml; do invalid_command "$x"; done
xargs
Ansatz funktioniert im Allgemeinen, bricht aber irgendwie beibash -c
Befehlen ab. Zum Beispiel:find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}"
. Dies wird mehrmals ausgeführt, währendfind . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}
es einmal ausgeführt wird und fehlschlägt. Irgendeine Idee warum?{}
drinnen verwendenbash -c
. Dadurch wird der Dateiname übernommen und direkt in den Shell-Befehl eingefügt. Wenn der Dateiname Zeichen enthält, die in der Shell eine besondere Bedeutung haben, z. B. Leerzeichen, interpretiert die Shell diese Sonderzeichen als solche. Wenn Sie eine Shell benötigen, übergeben Sie diese{}
als separates Argument, z. B.bash -c 'foo "$0"' {}
(beachten Sie auch die doppelten Anführungszeichen$0
).find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
find . -print0 | xargs -0 -n1 invalid_command
) -Ansatz. Dadurch wird auf dem ersten Fehler richtig:find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}
. Groß! Aber der gleiche Ansatz funktioniert nicht mitbash -c
(oben). Der einzige Unterschied zwischen den beiden istbash -c
.Ich kann dies stattdessen verwenden:
quelle
xargs
ist eine Option. Es ist jedoch eigentlich ganz einfach, dies auch zu tun,find
indem Sie+
anstelle von verwenden\;
Aus der POSIX-Dokumentation :
quelle