
O Linux set e pipefail comandos ditam o que acontece quando ocorre uma falha em um script Bash. Há mais em que pensar do que deveria parar ou continuar.
RELACIONADO: O Guia do Iniciante para Shell Scripting: O Básico
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.
O set e pipefile comandos permitem 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 This will happen first echo This will happen second
Para torná-lo executável, você precisará usar chmod:
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. Nós vamos perguntar ls para 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 This will happen first ls imaginary-filename echo This will happen second
Quando executamos este script, vemos a mensagem de erro de ls .
./script-2.sh

Apesar de ls comando falhou, 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 o $? variável que contém o último código de retorno enviado ao shell.
echo $?

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
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 diferente de zero é considerada uma falha.
Ao adicionar o set -e opção para o início do script, podemos alterar seu comportamento. Este é “script-3.sh.”
#!/bin/bash set -e echo This will happen first ls imaginary-filename echo This will happen second
Se executarmos este script veremos o efeito de set -e.
./script-3.sh
echo $?

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 o true e false shell embutido. Esses dois comandos não fazem mais do que gerar um código de retorno de zero ou um, respectivamente.
true
echo $?
false
echo $?

se nós canalizarmos false para dentro true -com false representando um processo falho – obtemos truecódigo de retorno de zero.
false | true
echo $?

Bash tem uma variável de matriz chamada PIPESTATUSe isso captura todos os códigos de retorno de cada programa na cadeia de tubulação.
false | true | false | true
echo "${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]} ${PIPESTATUS[3]}"

PIPESTATUS apenas 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 pipefail entre. Este é “script-4.sh”. Isso tentará canalizar o conteúdo de um arquivo que não existe para wc.
#!/bin/bash set -e echo This will happen first cat script-99.sh | wc -l echo This will happen second
Isso falha, como seria de esperar.
./script-4.sh
echo $?

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 echo comando.
Vamos adicionar no -o pipefail salve-o como “script-5.sh” e torne-o executável.
#!/bin/bash set -eo pipefail echo This will happen first cat script-99.sh | wc -l echo This will happen second
Vamos executar isso e verificar o código de retorno.
./script-5.sh
echo $?

O script para e o segundo echo comando não é executado. O código de retorno enviado ao shell é um, indicando corretamente uma falha.
RELACIONADO: Como usar o comando Echo no Linux
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 echo o valor de uma variável não inicializada, echo simplesmente 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 "Another echo command"
Vamos executá-lo e observar seu comportamento.
./script-6.sh
echo $?

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 o set -u opção (não definida). 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 "Another echo command"
Vamos executar o script:
./script-7.sh
echo $?

A variável não inicializada é detectada, o script é interrompido e o código de retorno é definido como um.
O -u (não definido) opção é inteligente o suficiente não ser acionado 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_Var é inicializado 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 o -u opção como o segundo opção na instrução set. O -o pipefail opção deve vir por último.
#!/bin/bash
set -euo pipefail
if [ -z "${New_Var:-}" ]; then
echo "New_Var has no value assigned to it."
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
default_value=484
Value=${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 é 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:-}" ]; then
echo "New_Var has no value assigned to it."
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.

