make 'find' retorna com um código de saída diferente de zero se o erro ocorreu

4

Por que estou vendo o seguinte:

$ find  -not -exec bash -c 'foo' \; -quit
bash: foo: command not found
$ echo $?
0

Esta é uma versão reduzida do script que estou usando e que publico no final da pergunta (se você realmente quiser saber).

Então, a questão é como eu faço find executar um shell usando exec bash -c em um grupo de resultados de busca e sair no primeiro que falha e também retorna uma saída diferente de zero código que eu posso inspecionar mais tarde no meu script?

* script real *

#!/usr/bin/env bash
find path-a path-b path-c \
  -iname build.xml -not -exec bash -c 'echo -n "building {} ..." && ant -f {} build && echo "success" || (echo "failure" && exit 1)' \; -quit
RESULT=$?
echo "result was $RESULT"
    
por Marcus Junius Brutus 05.09.2014 / 14:10

2 respostas

4

Isso faria isso:

#!/bin/bash
RESULT=0
while IFS= read -r -u3 -d $'
#!/bin/bash
RESULT=0
while IFS= read -r -u3 -d $'%pre%' file; do
        echo -n "building $file ..."
        ant -f "$file" build &&
           echo "success" ||
           { echo "failure" ; RESULT=1 ; break; }
done 3< <(find path-a path-b path-c  -print0)

echo "result was $RESULT"
' file; do echo -n "building $file ..." ant -f "$file" build && echo "success" || { echo "failure" ; RESULT=1 ; break; } done 3< <(find path-a path-b path-c -print0) echo "result was $RESULT"

Observe que ele mistura find com um loop bash , conforme mostrado aqui .

Ele não usa $? , mas usa diretamente a variável $RESULT .

Se tudo correr bem $RESULT é 0, senão é 1. O loop é interrompido assim que um erro é encontrado.

Espero que seja seguro contra nomes de arquivos maliciosos (devido ao uso de -print0 ).

    
por 05.09.2014 / 16:12
0

Se você é o comando find, você tem um trabalho difícil de fazer ao configurar seu código de saída. Isso porque você tem 2 entradas de tipos (esquecendo as opções no momento) com dois tipos de tarefas:

  1. O caminho (s) para os arquivos que você deseja encontrar. Você provavelmente não deseja, por exemplo, sair com um erro se tiver find /mnt/log/storage/place -type f -mtime +7 -print . É provável que EXISTEM arquivos no seu armazenamento de log com menos de 7 dias, portanto, não é um erro ignorá-los - essa é a sua intenção. Seria um erro se você não conseguisse entrar no caminho /mnt/log/storage/place .
  2. A expressão que controla as ações do find. Elementos na expressão são verdadeiros ou falsos. Para os propósitos de -exec , é verdade se o comando que está sendo executado retornar 0, false se ele retornar diferente de zero. Para alterar o comportamento de -exec , ele seria único entre todos os outros elementos de expressão encontrados, e provavelmente quebraria muitos dos scripts existentes existentes no mundo.

Assim, para outra solução para sua pergunta: você poderia fazer algo semelhante ao while loop do LatinSuD, em que você verifica o status do seu comando a partir de uma variável, mas muito mais simples:

errorout=$(find /tmp -type f \( -exec bash -c '/tmp/doit 1>/tmp/stdoutfile' \; -o -quit \) 2>&1 )

Se o script /tmp/doit não for executável ou produzir saída para stderr, a variável errorout será preenchida. Erro de teste e reagir como:

[ -n "$errorout" ] || { echo 'Oh no- an error from find!'; /do/something/else; }

Para um one-liner, você pode fazer isso:

errorout=$(find /tmp -type f \( -exec bash -c '/bin/false || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

Substitua /bin/false por um comando de sua escolha. Você pode executar uma lista de comandos assim:

errorout=$(find /tmp -type f \( -exec bash -c '{ command1 && command2 && command3; } || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

E se você não quiser sair imediatamente após a primeira falha de um comando na sua lista:

errorout=$(find /tmp -type f \( -exec bash -c '{ command1; command2; command3; } || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

... não esqueça os pontos-e-vírgulas antes das chaves de fechamento nas cadeias de comando.

    
por 19.05.2015 / 19:25