Como verificar se um comando foi bem-sucedido?

235

Existe alguma maneira de verificar se há um erro na execução de um comando?

Exemplo:

test1=`sed -i "/:@/c connection.url=jdbc:oracle:thin:@$ip:1521:$dataBase" $search`
valid $test1

function valid () {
  if $test -eq 1; then
    echo "OK"
    else echo "ERROR" 
  fi
}

Eu já tentei fazer isso, mas parece que não está funcionando. Eu não faço como isso.

moata_u
fonte
9
Prefira $ (foo) sobre backticks `foo` , porque você pode aninhar e é mais fácil distinguir dos apóstrofos.
usuário desconhecido
1
BTW, você precisa definir uma função ( valid) antes de chamá-la.
Wjandrea

Respostas:

345

O valor de retorno é armazenado em $?. 0 indica sucesso, outros indica erro.

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

Como qualquer outro valor textual, você pode armazená-lo em uma variável para comparação futura:

some_command
retval=$?
do_something $retval
if [ $retval -ne 0 ]; then
    echo "Return code was not zero but $retval"
fi

Para possíveis operadores de comparação, consulte man test.

Lekensteyn
fonte
Isso é legal ... posso segurar o erro de saída ?? !! , porque neste caso eu tenho 2 erro: erro de comando "text" ex, arquivo não encontrado e meu erro "text", que neste caso falhou por exemplo
moata_u 7/11/11
@moata_u: você pode armazenar o valor em uma variável, como mostrado na minha resposta.
precisa saber é o seguinte
@moata_u: Você precisa colocar um ;antes de elsee fi: `if ...; então ...; outro ...; fi
Lekensteyn 7/03/11
4
Este é um uso inútil detest .
David Foerster
1
@Blauhirn [ $? ](ou equivalente test $?) não funciona porque é $?avaliado como um número (0, 1 etc.) que não é nulo. Consulte a documentação paratest : "Se EXPRESSION for omitida, 'test' retornará false. Se EXPRESSION for um argumento único, 'test' retornará false se o argumento for nulo e true caso contrário."
Lekensteyn
87

Se você só precisa saber se o comando foi bem-sucedido ou falhou, não se preocupe em testar $?, basta testar o comando diretamente. Por exemplo:

if some_command; then
    printf 'some_command succeeded\n'
else
    printf 'some_command failed\n'
fi

E atribuir a saída a uma variável não altera o valor de retorno (bem, a menos que se comporte de maneira diferente quando stdout não é um terminal, é claro).

if output=$(some_command); then
    printf 'some_command succeded, the output was «%s»\n' "$output"
fi

http://mywiki.wooledge.org/BashGuide/TestsAndConditionals explica ifem mais detalhes.

Geirha
fonte
E se você quiser fazer algo diferente de ramificação, como armazenar o booleano se falhou ou não em um .ini? Então sua variável de saída não faz isso, mas $?faz, então você está incorreto ao dizer que testar o comando diretamente é estritamente melhor.
Timothy Swan
Atribuir a saída a uma variável pode alterar o valor de retorno quando alguém usa o localcomando, ou seja, local foo=$(false); echo $?;produz 0na saída. Mas localé relevante apenas dentro das funções do bash.
Cromax 22/01
26
command && echo OK || echo Failed
Abraham Sanchez
fonte
Se commandretorna erro na tela, como ocultá-lo?
Sigur
Se commandgravar erros no stderr, você poderá usar o formulário command 2> /dev/null && echo OK || echo Failed. O 2> /dev/nullredireciona a saída stderr para /dev/null. No entanto, alguns utilitários gravam erros no stdout (mesmo que seja uma prática ruim). Nesse caso, você pode omitir o 2 do redirecionamento, mas você perderá qualquer saída do comando. Esse método de verificação do sucesso é bom para uma lógica ternária simples, mas para um comportamento mais complexo, é melhor verificar o $?êxito do comando ou usar o ifmétodo de bloco descrito na resposta do @ geirha.
Bender the Greatest
17

$? deve conter o status de saída do comando anterior, que deve ser zero, sem erros.

Então, algo como;

cd /nonexistant
if [ $? -ne 0 ]
then
    echo failed
else
    echo success!
fi

na maioria dos casos, é mais fácil usar a construção && para encadear comandos que precisam depender um do outro. Portanto cd /nonexistant && echo success!, não ecoaria sucesso porque o comando quebra antes de &&. O corolário disso é ||, onde cd /nonexistant || echo fail o eco falharia porque o cd falhou. (isso se torna útil se você usar algo como || exit, que encerrará o script se o comando anterior falhar.)

Shaun
fonte
Isso é legal ... posso segurar o erro de saída ?? !! , porque nesse caso eu tenho 2 erro: erro de comando "text" ex, arquivo não encontrado e meu erro "text", que nesse caso falhou por exemplo
moata_u 7/11/11
@moata_u, consulte mywiki.wooledge.org/BashFAQ/002
geirha
5
command && echo $? || echo $?
modrobert
fonte
Você quer dizer command; echo $??
JavaScript é necessário
Não, minha linha está correta, fornece o código de resultado real como um número, independentemente de êxito ou falha.
modrobert
1
Ok, por favor, explique as diferenças para mim: true && echo $? || echo $?/ true; echo $?e false && echo $? || echo $?/ false; echo $?- você encontrará, eles fazem exatamente a mesma coisa: D
Javier Buzzi
Sim, o mesmo resultado, mas sem a condição. A pergunta original foi "Como verificar se um comando foi bem-sucedido?", Isso foi baseado em respostas anteriores. Eu acho que um exemplo melhor seria:command && echo "success: $?" || echo "fail: $?"
modrobert
5

Deve-se notar que if...then...fie &&/ ||tipo de abordagem lida com o status de saída retornado pelo comando que queremos testar (0 em caso de sucesso); no entanto, alguns comandos não retornam um status de saída diferente de zero se o comando falhar ou não puder lidar com a entrada. Isso significa que as abordagens usuais ife &&/ ||não funcionarão para esses comandos específicos.

Por exemplo, no Linux, o GNU fileainda sai com 0 se recebeu um arquivo não existente como argumento e findnão conseguiu localizar o usuário especificado.

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

Nesses casos, uma maneira potencial de lidarmos com a situação é lendo stderr/ stdinmensagens, por exemplo, aquelas que retornaram por filecomando ou analisam a saída do comando como em find. Para esse propósito, a caseinstrução pode ser usada.

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

(Esta é uma nova resposta da minha própria resposta sobre pergunta relacionada em unix.stackexchange.com )

Sergiy Kolodyazhnyy
fonte
1

Como mencionado em muitas outras respostas, um simples teste de $?fará, como este

if [ $? -eq 0 ]; then something; fi

Se você quiser testar se o comando falhou , use uma versão mais curta bash(mas talvez exagere) da seguinte maneira:

if (($?)); then something; fi

Isso funciona usando o (( ))modo aritmético, portanto, se o comando retornou success, ou seja $? = 0, o teste avalia para ((0))quais testes false, caso contrário, ele retornará true.

Para testar o sucesso , você pode usar:

if ! (($?)); then something; fi

mas já não é muito mais curto que o primeiro exemplo.

afuna
fonte
1
crítica construtiva?
afuna