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é?{}
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_command
enfoque 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
xargs
Es una opción. Sin embargo, en realidad es trivialmente fácil hacer estofind
también usando en+
lugar de\;
De la documentación POSIX :
fuente