No bash if
, todos os status de saída diferentes de zero são tratados como falsos. Mas frequentemente (como por exemplo em grep -q
), 1 é o único status que realmente significa falso, outros indicam erros.
Posso pensar nas seguintes alternativas à planície if "${cmd[@]}"; then echo yes; else echo no; fi
:
Simplescase
#!/usr/bin/env bash
set -o errexit -o pipefail
cmd=(bash -c 'exit 10')
st=0; "${cmd[@]}" || st=$?
case $st in
(0) echo yes;;
(1) echo no;;
(*) exit $st;;
esac
Verifique se há 0 ou 1
#!/usr/bin/env bash
set -o errexit -o pipefail
cmd=(bash -c 'exit 10')
st=0; "${cmd[@]}" || st=$?
[ $st -eq 0 -o $st -eq 1 ]
if [ $st -eq 0 ]; then
echo yes
else
echo no
fi
Função auxiliar para mapear status para saída
#!/usr/bin/env bash
set -o errexit -o pipefail
# Put this somewhere for reuse:
map-status() {
local st=0
"$@" || st=$?
case $st in
(0) echo t;;
(1) echo f;;
(*) return $st;;
esac
}
cmd=(bash -c 'exit 10')
st=$(map-status "${cmd[@]}") && if [ $st = t ]; then
echo yes
else
echo no
fi
Questões
Todos eles têm o problema de serem necessários
||
após o comando check, então errexit não está ativo no comando check. (Dependendo do comando, isso pode ser corrigido com um subshell com essa opção; mas um subshell não funciona quando o comando deve definir uma variável para uso posterior.) Como isso pode ser corrigido?Existem outras maneiras concisas de escrever um careful
if
? Alguma delas talvez seja considerada a maneira idiomática?
As soluções devem funcionar com as opções errexit e pipefail habilitadas.
Você só precisa testar de alguma forma especial se o status de saída de
grep
for diferente de zero, o que eu faço aqui noelif
branch daif
declaração. A expansão${status=$?}
expande para o valor de$?
e define o valor destatus
para o que$?
for. Isso tornastatus
disponível tanto para oelif
branch quanto para oelse
branch, você gostaria de usá-lo para algo.Ou, se você não quiser exibir ou usar o valor retornado de
grep
:O código acima funcionaria da mesma forma, independentemente de você executá-lo com
bash
e habilitar a configuraçãopipefail
ou aerrexit
configuração, já que o comando é executado como parte daif
declaração. Em geral, use apenaserrexit
com moderação, quando você tem uma série de comandos e não quer colocar|| exit
atrás de cada um deles (então desabilite a configuração novamente). Veja também o Bash FAQ de Greg Wooledge sobre isso.Se essa é a maneira "idiomática" de fazer isso, eu não sei. As pessoas geralmente não fazem diferença entre os status de saída não nulos de
grep
. No entanto, isso pode ser porque a diferença entregrep
dar erro egrep
não corresponder a um padrão em um arquivo pode não importar para a maioria dos scripts.Acho que você poderia fazer algo assim:
onde a função verifica explicitamente o status de retorno do comando fornecido antes de retornar.
Isso também funcionaria em outros contextos
careful whatever || ...
, mas não detectaria, por exemplo, erros de redirecionamento que acontecem antes da função ser chamada, mas acho que eles são definidos$?
como 1 de qualquer maneira (nos shells que tentei, incluindo Bash e zsh).A abordagem que costumo usar em meus scripts quando quero fazer algo assim é:
Essa abordagem é compatível com POSIX, o que significa que funciona EM TODO LUGAR (mesmo em todas as
sh
implementações do busybox notoriamente problemáticas) e também não se importa se o script em que está sendo executado define oerrfail
sinalizador ou não. Asafe_run
função encapsula o comando a ser executado de forma que, seset -o errfail
estiver habilitado, ele será desabilitado apenas o tempo suficiente para executar o comando encapsulado e salvar o código de retorno e, em seguida, reabilitado, preservando ainda a saída e o código de retorno.Eu também prefiro pessoalmente uma declaração de caso para esse tipo de coisa, pois é mais concisa do que uma
if
declaração e não exige salvar o código de saída ou depender de semântica que muitas pessoas desconhecem (embora seja provável que muitas pessoas não saibam o que$-
é, eu diria que a maioria das pessoas será capaz de inferir facilmente a partir do contexto o que é, enquanto o mesmo não é verdade para o tratamento de$?
conforme aplicado a condições emif
declarações).Dito isso, isso não é algo que acontece com muita frequência na minha experiência, a menos que você esteja lidando com um script que encapsula algum outro comando para fornecer uma interface mais útil para ele ou esteja invocando uma função ou comando que você mesmo escreveu e que usa o código de retorno para comunicar mais do que um simples status de aprovação/reprovação.