Come uscire da uno script di shell se una parte di esso fallisce?

Come posso scrivere uno script di shell che esce, se una parte di esso fallisce? Ad esempio, se il seguente snippet di codice non riesce, lo script dovrebbe terminare.

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

Answer

Un approccio potrebbe essere quello di aggiungere set -e allinizio dello script. Ciò significa (da help set):

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

Quindi se uno qualsiasi dei tuoi comandi fallisce, lo script verrà chiuso.

In alternativa, puoi aggiungere istruzioni exit nei possibili punti di errore:

command || exit 1 

Commenti

  • Io (e il wiki di bash ) preferirei che le persone pensassero alla corretta gestione degli errori invece di utilizzare la funzione set -e (non conforme alla progettazione IMO). Tuttavia, ' non si applica qui. LOP vuole uscire dallo script dopo 5 tentativi falliti di eseguire il comando.
  • @St é phaneChazelas Ho vinto ' Per discutere con te se ' non funziona, ' sono sicuro che ' re destra. Tuttavia, lOP ha chiesto " Come posso scrivere uno script di shell che esce, se una parte di esso fallisce? ", cosa ti rende pensi che ' stia per uscire dopo 5 errori?
  • perché ' t pensare a nessun altro modo la domanda può essere interpretata.
  • @St é phaneChazelas potresti avere ragione. Lho interpretato letteralmente: come può uscire lintero script se una parte di esso fallisce. E set -e è lunico modo che conosco per farlo.
  • In quello script snipet, i comandi che potrebbero attivare set -e è sleep (break essendo un builtin speciale causa la chiusura dello script in caso di errore nella maggior parte delle shell, i comandi in if o a sinistra di && non sono interessati da set -e, n=... potrebbe non riuscire se n è di sola lettura, ma ciò uscirebbe dallo script anche senza set -e), quindi linterpretazione sembra piuttosto improbabile. Sono daccordo che la domanda sia formulata male.

Risposta

Puoi uscire da uno script in qualsiasi punto utilizzando la parola chiave exit. Puoi anche specificare un codice di uscita per indicare ad altri programmi che o come lo script non è riuscito, ad es. exit 1 o exit 2 ecc. (Per convenzione, il codice di uscita 0 indica il successo e qualsiasi valore maggiore di 0 significa fallimento; tuttavia, anche per convenzione , i codici di uscita superiori a 127 sono riservati per la terminazione anomala (ad esempio tramite un segnale)).

La costruzione generica per uscire in caso di errore è

if [ failure condition ]; then exit n fi 

con failure condition e n. Ma in scenari specifici puoi procedere diversamente. Ora, per il tuo caso, interpreto la tua domanda secondo cui se una qualsiasi delle cinque invocazioni di gksu fallisce, allora intendi uscire. Un modo è utilizzare una funzione come questa

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

e quindi richiamare il ciclo con try_command.

Ci sono modi (più) avanzati o sofisticati per rispondere alla tua domanda. Tuttavia, la soluzione sopra è più accessibile ai principianti rispetto, ad esempio, alla soluzione di Stephane.

Risposta

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

exit esce dallo script a meno che non venga chiamato in una subshell. Se quella parte dello script è in una subshell, ad esempio perché “è allinterno di (...) o $(...) o parte di una pipe-line , allora uscirà solo da quella subshell .

In tal caso, se vuoi che lo script esca oltre alla subshell, allora ” Dovrò chiamare exit alluscita della subshell.

Ad esempio, qui con 2 livelli nidificati di subshell:

( 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 

Può diventare più complicato se la subshell fa parte di una pipeline. bash ha uno speciale $PIPESTATUS array, simile a zsh “s $pipestatus che può aiutarti qui:

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

Rispondi

Trap eseguirà unazione alla ricezione di un segnale.

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 

Eseguilo e lascialo uscire normalmente. Si intercetta al segnale 0.

EXIT 

Eseguilo di nuovo e interrompi con ^ C. Si intercetta sia sul segnale 2 che sul segnale 0.

CTL-C EXIT 

Uno stato di uscita diverso da zero verrà intercettato su ERR

ERR EXIT 

Risposta

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *