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ê?{}
dentrobash -c
. Isso pega o nome do arquivo e o insere diretamente dentro do comando shell. Se o nome do arquivo contiver caracteres que tenham um significado especial no shell, como espaços, o shell interpretará esses caracteres especiais como tal. Se você precisar de um shell, passe{}
como um argumento separado, por exemplobash -c 'foo "$0"' {}
(observe também as aspas duplas$0
).find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
find . -print0 | xargs -0 -n1 invalid_command
abordagem xargs ( ). Este pára no primeiro erro corretamente:find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}
. Ótimo! Mas a mesma abordagem não funcionabash -c
(acima). A única diferença entre os dois ébash -c
.Eu posso usar isso:
fonte
xargs
é uma opção. No entanto, também é trivialmente fácil fazer issofind
usando, em+
vez de\;
:Na documentação do POSIX :
fonte