Cum să ieșiți dintr-un script shell dacă o parte din acesta eșuează?

Cum pot scrie un script shell care iese, dacă o parte a acestuia eșuează? De exemplu, dacă următorul fragment de cod nu reușește, atunci scriptul ar trebui să iasă.

n=0 until [ $n -ge 5 ] do gksu *command* && break n=$[$n+1] sleep 3 

Răspuns

O abordare ar fi să adăugați set -e la începutul scriptului. Asta înseamnă (din help set):

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

Deci, dacă oricare dintre comenzile dvs. eșuează, scriptul va ieși.

Alternativ, puteți adăuga instrucțiuni explicite exit la posibilele puncte de eșec:

command || exit 1 

Comentarii

  • Eu (și wiki bash ) aș prefera ca oamenii să se gândească la gestionarea corectă a erorilor mai degrabă decât să folosiți caracteristica (ruptă de proiectarea IMO) set -e. ' nu se aplică cu adevărat aici. OP dorește să părăsească scriptul după 5 încercări nereușite de a rula comanda.
  • @St é phaneChazelas am câștigat ' nu mă cert cu privire la faptul dacă ' este stricat, sunt ' sigur că ' are dreptate. Cu toate acestea, OP a întrebat " Cum pot scrie un script shell care iese, dacă o parte a acestuia eșuează? ", ce te face cred că ' este despre ieșirea după 5 eșecuri?
  • pentru că nu pot ' să mă gândesc la alt mod întrebarea poate fi interpretată.
  • @St é phaneChazelas este posibil să aveți dreptate. L-am interpretat la propriu: cum poate ieși întregul script dacă o parte a acestuia eșuează. Și set -e este singurul mod în care știu să fac asta.
  • În acel fragment de script, comenzile care ar putea declanșa set -e este sleep (break fiind un program special încorporat, scriptul va ieși în caz de eșec în majoritatea shell-urilor, comenzile din sau în stânga && nu sunt afectate de set -e, n=... ar putea eșua dacă n este numai în citire, dar atunci ar ieși din script fără set -e și), astfel încât interpretarea sună destul de puțin probabil. Sunt de acord că întrebarea este slab formulată.

Răspuns

Puteți ieși dintr-un script în orice loc folosind cuvântul cheie exit. De asemenea, puteți specifica un cod de ieșire pentru a indica altor programe care sau cum a eșuat scriptul dvs., de ex. exit 1 sau exit 2 etc. (Prin convenție, codul de ieșire 0 este pentru succes și orice mai mare de 0 înseamnă eșec; totuși, de asemenea, prin convenție , codurile de ieșire de peste 127 sunt rezervate pentru terminarea anormală (de exemplu, printr-un semnal)).

Construcția generică de ieșire la eșec este

if [ failure condition ]; then exit n fi 

cu failure condition și n adecvate. Dar, în scenarii specifice, puteți proceda diferit. Acum, pentru cazul dvs., vă interpretez întrebarea că, dacă oricare dintre cele cinci invocații ale gksu eșuează, atunci doriți să ieșiți. O modalitate este de a utiliza o funcție ca aceasta

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

și apoi, invocați bucla prin try_command.

Există (mai) moduri avansate sau sofisticate de a vă adresa întrebării. Cu toate acestea, soluția de mai sus este mai accesibilă pentru începători decât, să zicem, soluția lui Stephane.

Răspuns

attempt=0 until gksu command; do attempt=$((attempt + 1)) if [ "$attempt" -gt 5 ]; then exit 1 fi done 

exit iese din script dacă nu este apelat într-un subshell. Dacă acea parte a scriptului se află într-un sub-shell, de exemplu, deoarece se află în (...) sau $(...) sau o parte a unei conducte , atunci va ieși numai din acel subshell .

În acest caz, dacă doriți ca script să iasă în plus față de subshell, atunci dvs. ” Va trebui să apelez exit la ieșirea acelui subshell.

De exemplu, aici cu 2 niveluri imbricate 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 

Poate deveni mai complicat dacă subshell-ul face parte dintr-o conductă. bash are un tablou special $PIPESTATUS, similar cu zsh „s $pipestatus unul care vă poate ajuta aici:

{ echo foo exit 1 echo bar } | wc -c subshell_ret=${PIPESTATUS[0]} if [ "$subshell_ret" -ne 0 ]; then exit "$subshell_ret" fi 

Răspuns

Trap va efectua o acțiune la primirea unui semnal.

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 

Rulați acest lucru și lăsați-l să iasă normal. Acesta captează semnalul 0.

EXIT 

Rulați-l din nou și întrerupeți-l cu ^ C. Captează atât semnalul 2, cât și semnalul 0.

CTL-C EXIT 

O stare de ieșire diferită de zero va fi captată pe ERR

ERR EXIT 

Răspuns

pass_to_functio() { echo "command exited with status $1" } ( exec <Any Command > & child_pid=$! wait $child_pid pass_to_function $? )& 

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *