Esta es una limitación de find
. El estándar POSIX especifica que el estado de retorno find
es 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 xargs
comandos 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 find
y 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 -e
para 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
xargs
enfoque funciona en general, pero de alguna manera se rompe en losbash -c
comandos. 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é?