Esta es una limitación de find. El estándar POSIX especifica que el estado de retorno findes 0 a menos que ocurra un error al recorrer los directorios; el estado de retorno de los comandos ejecutados no entra en él.
Puede hacer que los comandos escriban su estado en un archivo o en un descriptor:
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"
Otro método, como descubrió , es usar xargs. Los xargscomandos siempre procesan todos los archivos, pero devuelve el estado 1 si alguno de los comandos devuelve un estado distinto de cero.
find … -print0 | xargs -0 -n1 invalid_command
Sin embargo, otro método es evitar findy utilizar el engrosamiento recursivo en el shell: **/significa cualquier profundidad de subdirectorios. Esto requiere la versión 4 o superior de bash; macOS está atascado en la versión 3.x, por lo que tendría que instalarlo desde una colección de puertos. Use set -epara detener el script en el primer comando que devuelve un estado distinto de cero.
shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done
Tenga en cuenta que en bash 4.0 a 4.2, esto funciona pero atraviesa enlaces simbólicos a directorios, lo que generalmente no es deseable.
Si usa zsh en lugar de bash, el engrosamiento recursivo funciona de inmediato sin problemas. Zsh está disponible por defecto en OSX / macOS. En zsh, solo puedes escribir
set -e
for x in **/*.xml; do invalid_command "$x"; done
                 
                
xargsenfoque funciona en general, pero de alguna manera se rompe en losbash -ccomandos. Por ejemplo:find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}". Esto se ejecuta varias veces, mientras quefind . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}se ejecuta una vez y falla. ¿Alguna idea de por qué?{}interiorbash -c. Esto toma el nombre del archivo y lo inserta directamente dentro del comando de shell. Si el nombre del archivo contiene caracteres que tienen un significado especial en el shell, como espacios, el shell interpreta estos caracteres especiales como tales. Si necesita un shell, pase{}como un argumento separado, por ejemplobash -c 'foo "$0"' {}(tenga en cuenta también las comillas dobles$0).find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}find . -print0 | xargs -0 -n1 invalid_commandenfoque xargs ( ). Esto se detiene en el primer error correctamente:find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}. ¡Excelente! Pero el mismo enfoque no funciona conbash -c(arriba). La única diferencia entre los dos esbash -c.Puedo usar esto en su lugar:
fuente
xargsEs una opción. Sin embargo, en realidad es trivialmente fácil hacer estofindtambién usando en+lugar de\;De la documentación POSIX :
fuente