Categories: Tecnologia

Como usar set e pipefail em scripts Bash no Linux

fatmawati achmad zaenuri/Shutterstock.com

O Linux sete os pipefailcomandos ditam o que acontece quando ocorre uma falha em um script Bash . Há mais em que pensar do que deveria parar ou continuar.

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 precisam ser compilados. Qualquer ação repetitiva ou de vários estágios que você precise executar pode ser agrupada 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 utilitário ou programa externo. Se falhar, o utilitário externo será fechado e enviará um código de retorno ao shell, podendo até imprimir uma mensagem de erro no terminal. Mas seu script continuará sendo processado. Talvez não seja isso que você queria. 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 pipe, não daquele no meio que falhou. É claro que também podem ocorrer erros dentro do seu script, como tentar acessar uma variável não inicializada .

Os comandos sete pipefilepermitem que você decida o que acontece quando ocorrem erros como esses. Eles também permitem detectar erros mesmo quando ocorrem no meio de uma cadeia de tubulação.

Veja como usá-los.

Demonstrando o problema

Aqui está um script Bash trivial. Ele ecoa duas linhas de texto para o terminal. Você pode executar este script se copiar o texto em um editor e salvá-lo como “script-1.sh”.

#!/bin/bash

echo Isso vai acontecer primeiro
echo Isso acontecerá em segundo lugar

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

chmod +x script-1.sh

Você precisará executar esse comando em cada script 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 lspara listar os detalhes de um arquivo que não existe. Isso falhará. Nós salvamos isso como “script-2.sh” e o tornamos executável.

#!/bin/bash

echo Isso vai acontecer primeiro
ls nome-de-arquivo-imaginário
echo Isso acontecerá em segundo lugar

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

./script-2.sh

Embora o lscomando 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, o que indica sucesso. Podemos verificar isso usando echo e a $?variável que contém o último código de retorno enviado ao shell.

eco $?

O zero que é relatado é 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 em execução. Isso pode levar a outros problemas se o resto do script esperar ou depender da ação que falhou realmente foi bem-sucedida. E a segunda é que, se outro script ou processo precisar verificar o sucesso ou a falha desse script, ele obterá uma leitura falsa.

A opção set -e

A set -eopção (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 diferente de zero é considerada uma falha.

Adicionando a set -eopção ao início do script, podemos alterar seu comportamento. Este é “script-3.sh.”

#!/bin/bash
set -e

echo Isso vai acontecer primeiro
ls nome-de-arquivo-imaginário
echo Isso acontecerá em segundo lugar

Se executarmos este script, veremos o efeito do 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 em tubulações

A tubulação adiciona 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 à estaca zero. Esse código de retorno é perdido e o script continuará o processamento.

Podemos ver os efeitos dos comandos de tubulação com diferentes códigos de retorno usando os recursos internos truee do falseshell. Esses dois comandos não fazem mais do que gerar um código de retorno de zero ou um, respectivamente.

verdadeiro
eco $?
falso
eco $?

Se entrarmos — representando um processo falsecom falha — obteremos o código de retorno de zero.truefalsetrue

falso | verdadeiro
eco $?

O Bash tem uma variável de matriz chamada PIPESTATUS, e isso captura todos os códigos de retorno de cada programa na cadeia de tubos.

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

PIPESTATUSapenas mantém os 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 confuso muito rapidamente.

Este é o lugar onde set -o(opções) e pipefailentram. Este é “script-4.sh”. Isso tentará canalizar o conteúdo de um arquivo que não existe em wc.

#!/bin/bash
set -e

echo Isso vai acontecer primeiro
cat script-99.sh | wc -l
echo Isso acontecerá em segundo lugar

Isso falha, como seria de esperar.

./script-4.sh
eco $?

O primeiro zero é a saída de wc, nos dizendo que não leu nenhuma linha para o arquivo ausente. O segundo zero é o código de retorno do segundo echocomando.

Vamos adicionar o -o pipefailarquivo , salvá-lo como “script-5.sh” e torná-lo executável.

#!/bin/bash
set -eo pipefail

echo Isso vai 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 é interrompido e o segundo echocomando não é executado. O código de retorno enviado ao shell é um, indicando corretamente uma falha.

Capturando variáveis ​​não inicializadas

Variáveis ​​não inicializadas podem ser difíceis de identificar em um script do mundo real. Se tentarmos echoo valor de uma variável não inicializada, echosimplesmente imprime uma linha em branco. Não gera 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 passa pela variável não inicializada e continua a ser executado. O código de retorno é zero. Tentar encontrar um erro como esse em um script muito longo e complicado pode ser muito difícil.

Podemos capturar esse tipo de erro usando a set -uopção (unset). Vamos adicionar isso à nossa coleção crescente de opções definidas no topo 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 -uopção (unset) é inteligente o suficiente para não ser acionada por situações em que você pode interagir legitimamente com uma variável não inicializada.

Em “script-8.sh”, o script verifica se a variável New_Varestá inicializada ou não. Você não quer que o script pare aqui, em um script do mundo real, você executará processamento adicional e lidará com a situação você mesmo.

Observe que adicionamos a -uopção como a segunda opção na instrução set. A -o pipefailopção deve vir por último.

#!/bin/bash

set -euo pipefail

if [ -z "${New_Var:-}" ]; então

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 inicializada, um valor padrão é fornecido.

#!/bin/bash
set -euo pipefail

valor_padrão=484
Valor=${New_Var:-$default_value}
echo "New_Var=$Value"

Os scripts podem ser executados até sua 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 scripts, isso pode ser um salva-vidas. imprime os comandos e seus parâmetros à medida que são executados.

Ele fornece uma forma rápida e “pronta e pronta” de rastreamento de execução. Isolar falhas lógicas e detectar bugs se torna muito, muito mais fácil.

Adicionaremos 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:-}" ]; então
  echo "New_Var não tem valor atribuído a ela."
fi

Execute-o para ver as linhas de rastreamento.

./script-10.sh

Detectar bugs nesses scripts de exemplo triviais é fácil. Quando você começar a escrever scripts mais complexos, essas opções provarão seu valor.

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…

1 ano ago

Como reiniciar um PS4

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

1 ano 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ê…

1 ano 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…

1 ano 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…

1 ano ago

Como aumentar o zoom no Photoshop

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

1 ano ago