To ograniczenie find
. Standard POSIX określa, że zwracanym statusem find
jest 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 xargs
polecenia 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 find
i 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 -e
aby 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
xargs
Podejście działa w ogóle, ale w jakiś sposób łamie nabash -c
polecenia. 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?{}
środkubash -c
. Pobiera nazwę pliku i wstawia go bezpośrednio do polecenia powłoki. Jeśli nazwa pliku zawiera znaki, które mają specjalne znaczenie w powłoce, takie jak spacje, powłoka interpretuje te znaki specjalne jako takie. Jeśli potrzebujesz powłoki, przekaż ją{}
jako osobny argument, np.bash -c 'foo "$0"' {}
(Zwróć również uwagę na podwójne cudzysłowy$0
).find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
find . -print0 | xargs -0 -n1 invalid_command
podejście xargs ( ). Zatrzymuje się na pierwszym błędem poprawnie:find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}
. Świetny! Ale to samo podejście nie działa zbash -c
(powyżej). Jedyna różnica między nimi jestbash -c
.Zamiast tego mogę użyć tego:
źródło
xargs
jest jedną z opcji. Jednak w rzeczywistości jest to banalnie łatwe,find
używając również+
zamiast\;
Z dokumentacji POSIX :
źródło