Como posso escrever um script de shell que sai, se uma parte dele falhar? Por exemplo, se o snippet de código a seguir falhar, o script deve ser encerrado.
n=0 until [ $n -ge 5 ] do gksu *command* && break n=$[$n+1] sleep 3
Resposta
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 de 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
Comentários
Resposta
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; no entanto, também por convenção , os 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 em caso de falha é
if [ failure condition ]; then exit n fi
com failure condition
e n
adequados. Mas em cenários específicos, você pode proceder de forma diferente. Agora, para o seu caso, interpreto sua pergunta de que se qualquer uma das cinco invocações de gksu
falhar, você pretende 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, invocar o loop por try_command
.
Existem maneiras (mais) avançadas ou sofisticadas de como responder à sua pergunta. No entanto, a solução acima é mais acessível para iniciantes do que, digamos, a solução de Stephane.
Resposta
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 um subshell. Se essa parte do script estiver em um subshell, por exemplo, porque está dentro de (...)
ou $(...)
ou parte de uma tubulação , então ele só sairá daquele subshell .
Nesse caso, se você quiser que o script saia além do subshell, você ” Vou precisar chamar exit
na saída desse subshell.
Por exemplo, aqui com 2 níveis aninhados de subshells:
( 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 o subshell fizer parte de um pipeline. bash
tem uma matriz $PIPESTATUS
especial, semelhante a zsh
“s $pipestatus
que pode ajudá-lo aqui:
{ echo foo exit 1 echo bar } | wc -c subshell_ret=${PIPESTATUS[0]} if [ "$subshell_ret" -ne 0 ]; then exit "$subshell_ret" fi
Resposta
O Trap executará 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 e deixe-o sair normalmente. Ele intercepta o sinal 0.
EXIT
Execute-o novamente e interrompa com ^ C. Ele intercepta os sinais 2 e 0.
CTL-C EXIT
Um status de saída diferente de zero irá interceptar ERR
ERR EXIT
Resposta
pass_to_functio() { echo "command exited with status $1" } ( exec <Any Command > & child_pid=$! wait $child_pid pass_to_function $? )&
set -e
. Mas não ' realmente se aplica aqui. O OP deseja sair do script após 5 tentativas falhadas de executar o comando.set -e
é a única maneira que conheço de fazer isso.set -e
ésleep
(break
sendo um builtin especial faria com que o script fechasse em caso de falha na maioria dos shells, comandos emif
ou à esquerda de&&
não são afetados porset -e
,n=...
poderia falhar sen
fosse somente leitura, mas então isso sairia do script semset -e
também), de modo que interpretação parece bastante improvável. Eu concordo que a pergunta está mal formulada.