Como usar o conjunto e o PipeFail em scripts bash no Linux

Os comandos linux set e pipefail ditam o que acontece quando ocorre uma falha em um script Bash. Há mais em que pensar do que parar ou continuar.

RELACIONADO: O Guia do Iniciante para Shell Scripting: O Básico

índice

  1. Scripts Bash e Condições de Erro
  2. Demonstração do problema
  3. A opção set -e
  4. Lidando com falhas de tubulação
  5. Capturar variáveis ​​não inicializadas
  6. selado com machado

Scripts Bash e Condições de Erro

Os scripts de shell Bash são ótimos. Eles são rápidos para escrever e não requerem compilação. Qualquer ação repetitiva ou de vários estágios que você precise executar pode ser incluída em um script conveniente. E como os scripts podem chamar qualquer um dos utilitários padrão do Linux, você não está limitado aos recursos da própria linguagem shell.

Mas podem surgir problemas quando você chama um programa ou utilitário externo. Se falhar, o utilitário externo será encerrado e enviará um código de retorno ao shell e poderá até imprimir uma mensagem de erro no terminal. Mas seu script continuará sendo processado. Talvez não seja isso que você queira. Se ocorrer um erro no início da execução do script, isso poderá levar a problemas piores se o restante do script puder ser executado.

Você pode verificar o código de retorno de cada processo externo à medida que eles são concluídos, mas isso se torna difícil quando os processos são canalizados para outros processos. O código de retorno será do processo no final do pipeline, não do meio que falhou. Claro, erros também podem ocorrer em seu script, como tentar acessar uma variável não inicializada.

Os comandos set e pipefile permitem que você decida o que acontece quando ocorrem erros como esses. Eles também permitem que você detecte erros mesmo quando eles ocorrem no meio de uma cadeia de tubulação.

Veja como usá-los.

Demonstração do problema

Aqui está um script Bash trivial. Ecoa duas linhas de texto no terminal. Você pode executar este script copiando o texto em um editor e salvando-o como "script-1.sh".

 #!/bin/bash echo Isso acontecerá primeiro echo Isso acontecerá em segundo lugar

Para torná-lo executável, você precisará usar chmod :

 chmod +x script-1.sh

Você precisará executar esse comando em todos os scripts se quiser executá-los em seu computador. Vamos executar o script:

 ./script-1.sh

As duas linhas de texto são enviadas para a janela do terminal conforme o esperado.

Vamos modificar um pouco o script. pediremos a ls para listar os detalhes de um arquivo que não existe. Esta falha. Nós salvamos isso como "script-2.sh" e o tornamos executável.

 #!/bin/bash echo Isso acontecerá primeiro ls imaginário-filename echo Isso acontecerá em segundo lugar

Quando executamos esse script, vemos a mensagem de erro ls .

 ./script-2.sh

Embora o comando ls tenha falhado, o script continuou a ser executado. E mesmo que tenha ocorrido um erro durante a execução do script, o código de retorno do script para o shell é zero, indicando sucesso. Podemos verificar isso usando echo e o $? variável contendo o último código de retorno enviado ao shell.

 eco $?

O zero informado é o código de retorno do segundo eco no script. Portanto, há dois problemas com esse cenário. A primeira é que o script teve um erro, mas continuou a ser executado. Isso pode causar outros problemas se o resto do script esperar ou depender do sucesso da ação que falhou. E a segunda é que, se outro script ou processo precisar verificar o sucesso ou a falha desse script, ele receberá uma leitura falsa.

A opção set -e

O set -e (exit) faz com que um script saia se algum dos processos que ele chama gerar um código de retorno diferente de zero. Qualquer coisa que não seja zero é considerada uma falha.

Adicionando a opção set -e ao início do script, podemos alterar seu comportamento. Este é "script-3.sh".

 #!/bin/bash set -e echo Isso acontecerá primeiro ls imaginário-filename echo Isso acontecerá em segundo lugar

Se executarmos este script veremos o efeito de set -e .

 ./script-3.sh
 eco $?

O script é interrompido e o código de retorno enviado ao shell é um valor diferente de zero.

Lidando com falhas de tubulação

Os tubos adicionam mais complexidade ao problema. O código de retorno que sai de uma sequência canalizada de comandos é o código de retorno do último comando na cadeia. Se houver uma falha com um comando no meio da cadeia, voltamos ao ponto de partida. Esse código de retorno é perdido e o script continuará a ser processado.

Podemos ver os efeitos dos comandos de pipe com diferentes códigos de retorno usando o true e o false embutidos na caixa. Esses dois comandos não fazem nada além de gerar um código de retorno de zero ou um, respectivamente.

 verdadeiro
 eco $?
 falso
 eco $?

Se canalizarmos false para true -Com false representando um processo com falha, obteremos true O código de retorno de zero.

 falso | verdadeiro
 eco $?

Bash tem uma variável de array chamada PIPESTATUS e isso captura todos os códigos de retorno de cada programa na string de pipe.

 falso | verdadeiro | falso | verdadeiro
 echo "${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]} ${PIPESTATUS[3]}"

PIPESTATUS apenas retém códigos de retorno até que o próximo programa seja executado, e tentar determinar qual código de retorno combina com qual programa pode ficar muito complicado muito rapidamente.

É aqui que set -o (opções) e pipefail como em. Este é "script-4.sh". Isso tentará canalizar o conteúdo de um arquivo que não existe para wc .

 #!/bin/bash set -e echo Isso acontecerá primeiro cat script-99.sh | wc -l echo Isso acontecerá em segundo lugar

Isso falha, como esperado.

 ./script-4.sh
 eco $?

O primeiro zero é a saída de wc , informando que ele não leu nenhuma linha ausente do arquivo. O segundo zero é o código de retorno do segundo comando echo .

Vamos adicionar o -o pipefail salvá-lo como "script-5.sh" e torná-lo executável.

 #!/bin/bash set -eo pipefail echo Isso acontecerá primeiro cat script-99.sh | wc -l echo Isso acontecerá em segundo lugar

Vamos executar isso e verificar o código de retorno.

 ./script-5.sh
 eco $?

O script para e o segundo comando echo não é executado. O código de retorno enviado ao shell é um, indicando corretamente um erro.

RELACIONADO: Como usar o comando Echo no Linux

Capturar variáveis ​​não inicializadas

Variáveis ​​não inicializadas podem ser difíceis de detectar em um script do mundo real. se tentarmos echo o valor de uma variável não inicializada, echo simplesmente imprime uma linha em branco. Não lança uma mensagem de erro. O resto do script continuará a ser executado.

Este é o script-6.sh.

 #!/bin/bash set -eo pipefail echo "$notset" echo "Outro comando de eco"

Vamos executá-lo e observar seu comportamento.

 ./script-6.sh
 eco $?

O script substitui a variável não inicializada e continua em execução. O código de retorno é zero. Tentar encontrar um bug como esse em um script muito longo e complicado pode ser muito difícil.

Podemos detectar esse tipo de erro usando a opção set -u (unset). Vamos adicioná-lo à nossa coleção crescente de opções de configuração na parte superior do script, salvá-lo como "script-7.sh" e torná-lo executável.

 #!/bin/bash set -eou pipefail echo "$notset" echo "Outro comando de eco"

Vamos executar o script:

 ./script-7.sh
 eco $?

A variável não inicializada é detectada, o script é interrompido e o código de retorno é definido como um.

A opção -u (unset) é inteligente o suficiente para não ser acionada por situações em que pode interagir legitimamente com uma variável não inicializada.

Em "script-8.sh", o script verifica se a variável New_Var está inicializada ou não. Você não quer que o script pare aqui, em um script do mundo real você fará mais processamento e lidará com a situação você mesmo.

Observe que adicionamos a opção -u como a segunda opção na instrução set. A opção -o pipefail deve ser a última.

 #!/bin/bash set -euo pipefail if [ -z "${New_Var:-}" ]; then echo "New_Var não tem valor atribuído a ela." fi

Em "script-9.sh", a variável não inicializada é testada e, se não for, um valor padrão é fornecido.

 #!/bin/bash set -euo pipefail default_value=484 Value=${New_Var:-$default_value} echo "New_Var=$Value"

Os scripts podem ser executados até a conclusão.

 ./script-8.sh
 ./script-9.sh

selado com machado

Outra opção útil para usar é a opção set -x (executar e imprimir). Quando você está escrevendo roteiros, isso pode ser um salva-vidas. imprime os comandos e seus parâmetros à medida que são executados.

Ele oferece uma maneira rápida de rastrear a execução "durante o tempo". Isolar falhas lógicas e detectar erros torna-se muito, muito mais fácil.

Vamos adicionar a opção set -x a "script-8.sh", salvá-la como "script-10.sh" e torná-la executável.

 #!/bin/bash set -euxo pipefail if [ -z "${New_Var:-}" ]; then echo "New_Var não tem valor atribuído a ela." fi

Inicie-o para ver as linhas de rastreamento.

 ./script-10.sh

Detectar erros nesses scripts de exemplo triviais é fácil. À medida que você começa a escrever scripts mais complicados, essas opções provarão seu valor.

  • Excluir conta do Spotify permanentemente? Veja como fechar
  • Como excluir documentos e armazenamento de dados no iPhone no iOS 15

descubra mais conteúdo

Google Pixel Watch também tem detecção de queda, mas não até o próximo ano

As melhores xícaras de café aquecidas de 2022

Como automatizar seu iPhone com base na hora, atividade ou localização

"Isso deve ter sido antes do meu tempo"

Por que a NASA enviou Snoopy para a Lua? – Revisão Geek

O que é uma carga fantasma?

Ir arriba