Questa è una limitazione di find
. Lo standard POSIX specifica che lo stato di ritorno find
è 0 a meno che non si sia verificato un errore durante l'attraversamento delle directory; lo stato di ritorno dei comandi eseguiti non entra in esso.
Puoi fare in modo che i comandi scrivano il loro stato su un file o su un descrittore:
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"
Un altro metodo, come hai scoperto , è usare xargs. I xargs
comandi elaborano sempre tutti i file, ma restituiscono lo stato 1 se uno qualsiasi dei comandi restituisce uno stato diverso da zero.
find … -print0 | xargs -0 -n1 invalid_command
Ancora un altro metodo è quello di evitare find
e usare il globbing ricorsivo nella shell: **/
significa qualsiasi profondità delle sottodirectory. Ciò richiede la versione 4 o successiva di bash; macOS è bloccato alla versione 3.x quindi dovresti installarlo da una collezione di porte. Utilizzare set -e
per arrestare lo script sul primo comando che restituisce uno stato diverso da zero.
shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done
Attenzione che in bash da 4.0 a 4.2 funziona, ma attraversa i collegamenti simbolici alle directory, cosa che di solito non è desiderabile.
Se usi zsh invece di bash, il globbing ricorsivo funziona fuori dalla scatola senza gotchas. Zsh è disponibile per impostazione predefinita su OSX / macOS. In zsh, puoi semplicemente scrivere
set -e
for x in **/*.xml; do invalid_command "$x"; done
xargs
approccio funziona in generale, ma in qualche modo si rompe suibash -c
comandi. Ad esempio:find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}"
. Questo viene eseguito più volte mentrefind . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}
viene eseguito una volta e non riesce. Qualche idea sul perché?