Como sair de um script de shell se uma parte dele falhar?

34

Como posso escrever um script de shell que sai se uma parte dele falhar? Por exemplo, se o seguinte trecho de código falhar, o script deverá sair.

n=0
until [ $n -ge 5 ]
do
  gksu *command* && break
  n=$[$n+1]
  sleep 3
    
por Weylyn 12.09.2016 / 10:52

4 respostas

68

Uma abordagem seria adicionar set -e ao início do seu script. Isso significa (de help set ):

  -e  Exit immediately if a command exits with a non-zero status.

Portanto, se algum dos seus comandos falhar, o script será encerrado.

Como alternativa, você pode adicionar instruções exit explícitas nos possíveis pontos de falha:

command || exit 1
    
por 12.09.2016 / 11:22
15

Você pode sair de um script em qualquer lugar usando a palavra-chave exit . Você também pode especificar um código de saída para indicar a outros programas que ou como seu script falhou, por exemplo, exit 1 ou exit 2 etc. (Por convenção, o código de saída 0 é para sucesso e qualquer coisa maior que 0 significa falha; entretanto, também por convenção, códigos de saída acima de 127 são reservados para finalização anormal (por exemplo, por um sinal)).

A construção genérica para sair com falha é

if [ failure condition ]; then
    exit n
fi

com failure condition e n adequados. Mas em cenários específicos, você pode proceder de maneira diferente. Agora, para o seu caso, eu interpreto sua pergunta de que, se alguma das cinco invocações de gksu falhar, você quer sair. Uma maneira é usar uma função como esta

function try_command {
    for i in 1 2 3 4 5 ; do
        if gksu command ; then
            return 0
        fi
    fi
    exit 1
}

e, em seguida, invoque o loop por try_command .

Existem (mais) formas avançadas ou sofisticadas de como abordar sua pergunta. No entanto, a solução acima é mais acessível para iniciantes do que, digamos, a solução de Stephane.

    
por 12.09.2016 / 11:34
10
attempt=0
until gksu command; do
  attempt=$((attempt + 1))
  if [ "$attempt" -gt 5 ]; then
    exit 1
  fi
done

exit sai do script, a menos que seja chamado em uma subchave. Se essa parte do script estiver em um subshell, por exemplo, porque ela está dentro de (...) ou $(...) ou parte de um pipe, então sairá apenas dessa subshell .

Nesse caso, se você quiser que o script saia além do subnível, será necessário chamar exit após a saída da subshell.

Por exemplo, aqui com 2 níveis aninhados de subpastas:

(
  life=hard
  output=$(
    echo blah
    [ "$life" = easy ] || exit 1 # exit subshell
    echo blih not run
  ) || exit # if the subshell exits with a non-zero exit status,
            # exit as well with the same exit status

  echo not run either
) || exit # if the subshell exits with a non-zero exit status,
          # exit as well with the same exit status

Pode se tornar mais complicado se a subshell fizer parte de um pipeline. bash tem uma matriz especial $PIPESTATUS , semelhante a zsh ' $pipestatus one que pode ajudar você aqui:

{
   echo foo
   exit 1
   echo bar
} | wc -c
subshell_ret=${PIPESTATUS[0]}
if [ "$subshell_ret" -ne 0 ]; then
  exit "$subshell_ret"
fi
    
por 12.09.2016 / 11:21
2

O trap efetua uma ação ao receber um sinal.

trap "echo EXIT;  exit" 0
trap "echo HUP;   exit" 1
trap "echo CTL-C; exit" 2
trap "echo QUIT;  exit" 3
trap "echo ERR;   exit" ERR
n=0
until [ $n -ge 5 ]
do
  n=$[$n+1]
  echo $n
  sleep 3
done

Execute isso e deixe-o sair normalmente. Ele captura o sinal 0.

EXIT

Execute novamente e interrompa com ^ C. Ele captura o sinal 2 e o sinal 0.

CTL-C
EXIT

Um status de saída diferente de zero será capturado em ERR

ERR
EXIT
    
por 13.09.2016 / 02:56