Estou escrevendo um script no Bash para testar algum código. No entanto, parece tolo executar os testes se a compilação do código falhar em primeiro lugar; nesse caso, eu simplesmente abortarei os testes.
Existe uma maneira de fazer isso sem envolver o script inteiro dentro de um loop while e usar quebras? Algo como um dun dun dun goto?
1
consistente. Se o script for executado por outro script, convém definir seu próprio conjunto de códigos de status com um significado específico. Por exemplo,1
== testes falharam,2
== falha na compilação. Se o script fizer parte de outra coisa, pode ser necessário ajustar os códigos para corresponder às práticas usadas lá. Por exemplo, quando parte do conjunto de testes é executada pela automake, o código77
é usado para marcar um teste como ignorado.exit #
comando dentro de uma função, não de um script. (Nesse caso, use-oreturn #
.)exit 0
sair do script e retorna 0 (contando outros scripts que possam utilizar o resultado deste roteiro foi bem sucedido)Use set -e
O script será encerrado após a primeira linha que falhar (retorna código de saída diferente de zero). Nesse caso, o comando that-fail2 não será executado.
Se você verificar o status de retorno de cada comando, seu script terá a seguinte aparência:
Com set -e , seria semelhante a:
Qualquer comando que falhar fará com que o script inteiro falhe e retorne um status de saída que você pode verificar com $? . Se o seu script for muito longo ou você estiver criando muitas coisas, ficará muito feio se você adicionar verificações de status de retorno em todos os lugares.
fonte
set -e
Você ainda pode fazer alguns comandos saída com erros sem interromper o script:command 2>&1 || echo $?
.set -e
abortará o script se um pipeline ou estrutura de comando retornar um valor diferente de zero. Por exemplofoo || bar
, falhará apenas se ambosfoo
ebar
retornarem um valor diferente de zero. Geralmente, um script bash bem escrito funcionará se você adicionarset -e
no início e a adição funcionar como uma verificação de integridade automática: interrompa o script se algo der errado.set -o pipefail
opçãoset -e
seria justomake || exit $?
.set -u
. Dê uma olhada ao unofficial modo estrito festa :set -euo pipefail
.Um cara do SysOps me ensinou uma vez a técnica da garra com três dedos:
Essas funções são * NIX OS e shell-robustas. Coloque-os no início do seu script (bash ou não),
try()
sua declaração e código.Explicação
(com base no comentário de ovelhas voadoras ).
yell
: imprima o nome do script e todos os argumentos parastderr
:$0
é o caminho para o script;$*
são todos argumentos.>&2
significa>
redirecionar stdout para o & pipe2
. tubo1
seria emstdout
si.die
faz o mesmo queyell
, mas sai com um status de saída diferente de 0 , o que significa "falha".try
usa o||
(booleanoOR
), que avalia apenas o lado direito se o esquerdo falhar.$@
é todos os argumentos novamente, mas diferentes .fonte
$0
é o caminho para o script.$*
são todos argumentos.>&2
significa ">
redirecionar stdout para&
canal2
". o tubo 1 seria o próprio padrão. então grite prefixo todos os argumentos com o nome do script e imprima para stderr. die faz o mesmo que gritar , mas sai com um status de saída diferente de 0, o que significa "falha". try usa o booleano ou||
, que avalia apenas o lado direito se o esquerdo não falhar.$@
é todos os argumentos novamente, mas diferentes . esperança de que explica tudodie() { yell "$1"; exit $2; }
que você possa passar uma mensagem e sair com o códigodie "divide by zero" 115
.yell
edie
. No entanto,try
nem tanto. Você pode fornecer um exemplo de como usá-lo?Se você chamar o script
source
, poderá usarreturn <x>
where<x>
estará o status de saída do script (use um valor diferente de zero para erro ou falso). Mas se você chamar um script executável (ou seja, diretamente com seu nome de arquivo), a declaração de retorno resultará em uma reclamação (mensagem de erro "return: pode apenas 'retornar' de uma função ou script de origem").Se
exit <x>
for usado, quando o script for chamadosource
, resultará na saída do shell que iniciou o script, mas um script executável será encerrado, conforme o esperado.Para lidar com ambos os casos no mesmo script, você pode usar
Isso manipulará qualquer chamada que seja adequada. Isso pressupõe que você usará essa declaração no nível superior do script. Eu desaconselharia a saída direta do script de dentro de uma função.
Nota:
<x>
é suposto ser apenas um número.fonte
Costumo incluir uma função chamada run () para lidar com erros. Cada chamada que eu quero fazer é passada para essa função, para que o script inteiro saia quando uma falha for atingida. A vantagem disso sobre a solução set -e é que o script não sai silenciosamente quando uma linha falha e pode lhe dizer qual é o problema. No exemplo a seguir, a terceira linha não é executada porque o script sai na chamada para false.
fonte
set -e option
. Em seguida, o comando, uma vez que é com argumentos, eu usei aspas simples para evitar problemas festança assim:runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'
. Nota: alterei o nome da função para runTry.eval
é potencialmente perigoso se você aceitar entradas arbitrárias, mas, caso contrário, isso parecerá muito bom.Em vez de
if
construir, você pode aproveitar a avaliação de curto-circuito :Observe o par de parênteses necessário devido à prioridade do operador de alternância.
$?
é uma variável especial configurada para sair do código do comando chamado mais recentemente.fonte
command -that --fails || exit $?
isso sem parênteses, oecho $[4/0]
que nos leva a precisar deles?echo $[4/0] || exit $?
) bash nunca executará oecho
, e muito menos obedecerá ao||
.Eu tenho a mesma pergunta, mas não posso perguntar, porque seria uma duplicata.
A resposta aceita, usando exit, não funciona quando o script é um pouco mais complicado. Se você usar um processo em segundo plano para verificar a condição, a saída sai apenas desse processo, pois ele é executado em um subcasca. Para matar o script, você deve explicitamente matá-lo (pelo menos é o único jeito que eu sei).
Aqui está um pequeno script sobre como fazê-lo:
Esta é uma resposta melhor, mas ainda incompleta. Realmente não sei como me livrar da parte do boom .
fonte