To ograniczenie find. Standard POSIX określa, że zwracanym statusem findjest 0, chyba że wystąpił błąd podczas przeglądania katalogów; status powrotu wykonanych poleceń nie wchodzi w to.
Możesz sprawić, aby polecenia zapisywały swój status do pliku lub do deskryptora:
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"
Inną metodą, jak odkryłeś , jest użycie xargs. Te xargspolecenia zawsze przetwarza wszystkie pliki, ale zwraca status 1 Jeśli jakieś polecenie zwraca stan niezerowe.
find … -print0 | xargs -0 -n1 invalid_command
Jeszcze inną metodą jest unikanie findi stosowanie rekurencyjnego globowania w powłoce zamiast: **/oznacza dowolną głębokość podkatalogów. Wymaga to wersji 4 lub wyższej bash; macOS utknął w wersji 3.x, więc musisz zainstalować go z kolekcji portów. Użyj, set -eaby zatrzymać skrypt dla pierwszego polecenia zwracającego niezerowy status.
shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done
Uwaga: w wersjach bash 4.0 do 4.2 działa to, ale przegląda dowiązania symboliczne do katalogów, co zwykle nie jest pożądane.
Jeśli użyjesz zsh zamiast bash, rekurencyjne globowanie działa natychmiast po wyjęciu z pudełka bez żadnych błędów. Zsh jest domyślnie dostępny na OSX / macOS. W Zsh możesz po prostu pisać
set -e
for x in **/*.xml; do invalid_command "$x"; done
xargsPodejście działa w ogóle, ale w jakiś sposób łamie nabash -cpolecenia. Na przykład:find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}". Jest to wykonywane wielokrotnie, podczas gdyfind . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}jest wykonywane raz i kończy się niepowodzeniem. Masz pomysł, dlaczego?