Esta é uma limitação de find
. O padrão POSIX especifica que o status de retorno find
é 0, a menos que ocorreu um erro ao percorrer os diretórios; o status de retorno dos comandos executados não entra nele.
Você pode fazer com que os comandos gravem seus status em um arquivo ou em um descritor:
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"
Outro método, como você descobriu , é usar xargs. Os xargs
comandos sempre processam todos os arquivos, mas retornam o status 1 se algum dos comandos retornar um status diferente de zero.
find … -print0 | xargs -0 -n1 invalid_command
Ainda outro método é evitar find
e usar globbing recursivo no shell: **/
significa qualquer profundidade de subdiretórios. Isso requer a versão 4 ou superior do bash; O macOS está bloqueado na versão 3.x, portanto você precisa instalá-lo a partir de uma coleção de portas. Use set -e
para interromper o script no primeiro comando, retornando um status diferente de zero.
shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done
Observe que, no bash 4.0 a 4.2, isso funciona, mas percorre links simbólicos para diretórios, o que geralmente não é desejável.
Se você usar o zsh em vez do bash, o globbing recursivo funciona imediatamente, sem truques. O Zsh está disponível por padrão no OSX / macOS. No zsh, você pode simplesmente escrever
set -e
for x in **/*.xml; do invalid_command "$x"; done
xargs
abordagem funciona em geral, mas de alguma forma quebra osbash -c
comandos. Por exemplo:find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}"
. Isso é executado várias vezes, enquantofind . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}
é executado uma vez e falha. Alguma idéia do porquê?