Categories: Tecnologia

Como capturar erros em scripts Bash no Linux

fatmawati achmad zaenuri/Shutterstock.com

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.

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 chmodcomando. 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 NOToperador lógico — o corpo da ifinstruçã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 1linha é redundante. Afinal, não há mais nada no script e ele terminará de qualquer maneira. Mas usar o exitcomando 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 ORcom 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 ORo 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_commandque obviamente falha, então o comando à direita do ORoperador lógico, ||, é executado. Isso chama a error_handlerfunçã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_handlerfunçã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_handlermeio de “comando não encontrado”. Se quiséssemos, poderíamos usar isso como o status de saída do script, passando-o para o exitcomando.

Outra abordagem seria expandir error_handlerpara 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 setcomando com a -eopçã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 -Eopçã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 -uopção (unset). Para certificar-se de que os erros sejam detectados em sequências canalizadas, adicione a -o pipefailopçã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 pipefailopçã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 echocomando 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 SIGINTque é 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 trapcomando contém um echocomando e o exitcomando. Ele será acionado quando SIGINTfor levantado. O resto do script é um loop simples. Se você executar o script e pressionar Ctrl+C, verá a mensagem da trapdefinição e o script será encerrado.

./sigint.sh

Podemos usar trapcom o ERRsinal 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 mainfunção, que chama as funções seconde third. Quando um erro é encontrado—neste caso, porque bad_commandnão existe—a trapinstrução direciona o erro para a error_handlerfunção. Ele passa o status de saída do comando com falha e o número da linha para a error_handlerfunção.

./trap.sh

Nossa error_handlerfunção simplesmente lista os detalhes do erro na janela do terminal. Se desejar, você pode adicionar um exitcomando à função para que o script seja encerrado. Ou você pode usar uma série de if/elif/fiinstruçõ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 .

maisroot

Recent Posts

O novo aplicativo “PC Manager” da Microsoft se parece muito com o CCleaner

Muitos aplicativos de limpeza estão disponíveis para Windows ao longo dos anos, mas hoje em…

7 meses ago

Como reiniciar um PS4

Seu PlayStation 4 está congelado? Seus jogos favoritos continuam travando? Reiniciar seu PS4 pode resolver…

7 meses ago

Veja por que as reticências são tão assustadoras ao enviar mensagens de texto…

A popularidade das mensagens de texto significou aprender uma forma totalmente nova de comunicação. Você…

7 meses ago

O telescópio James Webb acaba de capturar os “Pilares da Criação”

A foto dos "Pilares da Criação" tirada pelo Telescópio Espacial Hubble é uma das fotos…

7 meses ago

Você poderá baixar o Proton Drive mais cedo do que pensa

O Proton Drive saiu de seu estágio beta há algumas semanas, mas o aplicativo real…

7 meses ago

Como aumentar o zoom no Photoshop

Para ver suas fotos mais de perto ou para uma edição precisa , você pode…

7 meses ago