Por padrão, um script Bash no Linux relatará um erro, mas continuará em execução. Mostramos a você como lidar com erros para que você possa decidir o que precisa acontecer em seguida.
Índice
Tratamento de erros em scripts
O tratamento de erros faz parte da programação. Mesmo se você escrever um código sem falhas, ainda poderá encontrar condições de erro. O ambiente em seu computador muda com o tempo, à medida que você instala e desinstala software, cria diretórios e executa upgrades e atualizações.
Por exemplo, um script que costumava ser executado sem problemas pode ter dificuldades se os caminhos do diretório forem alterados ou as permissões forem alteradas em um arquivo . A ação padrão do shell Bash é imprimir uma mensagem de erro e continuar a executar o script. Este é um padrão perigoso.
Se a ação que falhou for crítica para algum outro processamento ou ação que acontece posteriormente em seu script, essa ação crítica não será bem-sucedida. Quão desastroso isso se torna, depende do que seu script está tentando fazer.
Um esquema mais robusto detectaria erros e permitiria que o script funcionasse se fosse necessário desligar ou tentar remediar a condição de falha. Por exemplo, se um diretório ou arquivo estiver ausente, pode ser satisfatório que o script os recrie.
Se o script encontrou um problema do qual não pode se recuperar, ele pode ser encerrado. Se o script precisar ser encerrado, ele poderá executar qualquer limpeza necessária, como remover arquivos temporários ou gravar a condição de erro e o motivo do encerramento em um arquivo de log.
Detectando o status de saída
Comandos e programas geram um valor que é enviado ao sistema operacional quando são encerrados. Isso é chamado de status de saída . Tem um valor de zero se não houver erros, ou algum valor diferente de zero se ocorreu um erro.
Podemos verificar o status de saída — também conhecido como código de retorno — dos comandos que o script usa e determinar se o comando foi bem-sucedido ou não.
No Bash, zero equivale a verdadeiro. Se a resposta do comando não for verdadeira, sabemos que ocorreu um problema e podemos tomar as medidas apropriadas.
Copie este script em um editor e salve-o em um arquivo chamado “bad_command.sh”.
#!/bin/bash if (! bad_command); então echo "bad_command sinalizou um erro." saída 1 fi
Você precisará tornar o script executável com o chmod
comando. Esta é uma etapa necessária para tornar qualquer script executável, portanto, se você quiser experimentar os scripts em sua própria máquina, lembre-se de fazer isso para cada um deles. Substitua o nome do script apropriado em cada caso.
chmod +x bad_command.sh
Quando executamos o script, vemos a mensagem de erro esperada.
./bad_command.sh
Não existe um comando como “bad_command”, nem é o nome de uma função dentro do script. Ele não pode ser executado, então a resposta não é zero. Se a resposta não for zero — o ponto de exclamação é usado aqui como o NOT
operador lógico — o corpo da if
instrução é executado.
Em um script do mundo real, isso pode encerrar o script, o que nosso exemplo faz, ou pode tentar remediar a condição de falha.
Pode parecer que a exit 1
linha é redundante. Afinal, não há mais nada no script e ele terminará de qualquer maneira. Mas usar o exit
comando nos permite passar um status de saída de volta ao shell. Se nosso script for chamado de dentro de um segundo script, esse segundo script saberá que esse script encontrou erros.
Você pode usar o operador lógico OR
com o status de saída de um comando e chamar outro comando ou uma função em seu script se houver uma resposta diferente de zero do primeiro comando.
comando_1 || comando_2
Isso funciona porque o primeiro comando executa OR
o segundo. O comando mais à esquerda é executado primeiro. Se for bem-sucedido, o segundo comando não será executado. Mas se o primeiro comando falhar, o segundo comando será executado. Assim, podemos estruturar o código assim. Este é “lógico-ou./sh.”
#!/bin/bash error_handler() { echo "Erro: ($?) $1" saída 1 } bad_command || error_handler "bad_command falhou, Linha: ${LINENO}"
Definimos uma função chamada error_handler
. Isso imprime o status de saída do comando com falha, mantido na variável $?
e uma linha de texto que é passada para ele quando a função é chamada. Isso é mantido na variável $1
. A função termina o script com um status de saída de um.
O script tenta executar o bad_command
que obviamente falha, então o comando à direita do OR
operador lógico, ||
, é executado. Isso chama a error_handler
função e passa uma string que nomeia o comando que falhou e contém o número da linha do comando com falha.
Executaremos o script para ver a mensagem do manipulador de erros e, em seguida, verificaremos o status de saída do script usando echo.
./logical-or.sh
eco $?
Nossa pequena error_handler
função fornece o status de saída da tentativa de execução bad_command
, o nome do comando e o número da linha. Esta é uma informação útil quando você está depurando um script.
O status de saída do script é um. O status de saída 127 relatado por error_handler
meio de “comando não encontrado”. Se quiséssemos, poderíamos usar isso como o status de saída do script, passando-o para o exit
comando.
Outra abordagem seria expandir error_handler
para verificar os diferentes valores possíveis do status de saída e executar diferentes ações de acordo, usando este tipo de construção:
exit_code=$? if [ $exit_code -eq 1]; então echo "Operação não permitida" elif [ $exit_code -eq 2 ]; então echo "Uso indevido de shell embutido" . . . elif [ $status -eq 128 ]; então echo "Argumento inválido" fi
Usando set para forçar uma saída
Se você sabe que deseja que seu script saia sempre que houver um erro, você pode forçá-lo a fazer isso. isso significa que você abre mão da chance de qualquer limpeza — ou qualquer dano adicional também — porque seu script termina assim que detecta um erro.
Para fazer isso, use o set
comando com a -e
opção (erro). Isso diz ao script para sair sempre que um comando falhar ou retornar um código de saída maior que zero. Além disso, o uso da -E
opção garante que a detecção de erros e o trapping funcionem nas funções do shell.
Para também capturar variáveis não inicializadas, adicione a -u
opção (unset). Para certificar-se de que os erros sejam detectados em sequências canalizadas, adicione a -o pipefail
opção. Sem isso, o status de saída de uma sequência de comandos canalizada é o status de saída do comando final na sequência. Um comando com falha no meio da sequência canalizada não seria detectado. A -o pipefail
opção deve vir na lista de opções.
A sequência a ser adicionada ao topo do seu script é:
set -Eeuo pipefail
Aqui está um pequeno script chamado “unset-var.sh”, com uma variável unset nele.
#!/bin/bash set -Eeou pipefail echo "$unset_variable" echo "Nós vemos esta linha?"
Quando executamos o script, a unset_variable é reconhecida como uma variável não inicializada e o script é finalizado.
./unset-var.sh
O segundo echo
comando nunca é executado.
Usando trap com erros
O comando Bash trap permite nomear um comando ou uma função que deve ser chamada quando um sinal específico é gerado. Normalmente, isso é usado para capturar sinais, como o SIGINT
que é gerado quando você pressiona a combinação de teclas Ctrl+C. Este script é “sigint.sh”.
#!/bin/bash trap "echo -e '\nTerminado por Ctrl+c'; sair" SIGINT contador=0 enquanto verdadeiro Faz echo "Número do loop:" $((++contador)) dormir 1 feito
O trap
comando contém um echo
comando e o exit
comando. Ele será acionado quando SIGINT
for levantado. O resto do script é um loop simples. Se você executar o script e pressionar Ctrl+C, verá a mensagem da trap
definição e o script será encerrado.
./sigint.sh
Podemos usar trap
com o ERR
sinal para detectar erros à medida que eles ocorrem. Estes podem então ser alimentados a um comando ou função. Este é “trap.sh”. Estamos enviando notificações de erro para uma função chamada error_handler
.
#!/bin/bash trap 'error_handler $? $LINENO' ERR error_handler() { echo "Erro: ($1) ocorreu em $2" } a Principal() { echo "Dentro da função main()" bad_command segundo terceiro sair $? } segundo() { echo "Após a chamada para main()" echo "Dentro da função second()" } terceiro() { echo "Dentro da função third()" } a Principal
A maior parte do script está dentro da main
função, que chama as funções second
e third
. Quando um erro é encontrado—neste caso, porque bad_command
não existe—a trap
instrução direciona o erro para a error_handler
função. Ele passa o status de saída do comando com falha e o número da linha para a error_handler
função.
./trap.sh
Nossa error_handler
função simplesmente lista os detalhes do erro na janela do terminal. Se desejar, você pode adicionar um exit
comando à função para que o script seja encerrado. Ou você pode usar uma série de if/elif/fi
instruções para executar ações diferentes para erros diferentes.
Pode ser possível corrigir alguns erros, outros podem exigir que o script pare.
Uma dica final
Capturar erros geralmente significa antecipar as coisas que podem dar errado e colocar um código para lidar com essas eventualidades, caso surjam. Isso além de garantir que o fluxo de execução e a lógica interna do seu script estejam corretos.
Se você usar este comando para executar seu script, o Bash mostrará uma saída de rastreamento à medida que o script é executado:
bash -x seu-script.sh
O Bash grava a saída de rastreamento na janela do terminal. Ele mostra cada comando com seus argumentos – se houver algum. Isso acontece após os comandos serem expandidos, mas antes de serem executados.
Pode ser uma tremenda ajuda no rastreamento de bugs indescritíveis .