Come fermare lo script bash quando una condizione fallisce?


11

Qui mostra come usare ||e &&in una sola riga per concatenare l'esecuzione dei comandi: Come posso verificare la presenza di errori apt-get in uno script bash?

Sto cercando di interrompere l'esecuzione di uno script se una determinata condizione fallisce,

per esempio

false || echo "Obvious error because its false on left" && exit

Qui stampa Obvious error because its false on the lefted esce dalla console che è quello che volevo.

true || echo "This shouldn't print" && exit

Qui, non c'è alcuna stampa echo ma anche il exitcomando viene eseguito, ovvero la console è chiusa, il exitcomando non deve essere eseguito perché il comando echo sulla destra non è stato eseguito? Oppure, per impostazione predefinita, un'istruzione è considerata falsa sul lato sinistro di un &&operatore?

Modifica: avrei dovuto menzionarlo prima, il mio obiettivo era echeggiare l'errore ed uscire se non fosse chiaro. scritto nel mio caso specifico di rilevazione di errori quando si raggruppano le condizioni usando && e ||, la risposta di @ bodhi.zazen risolve il problema.

La risposta di @takatakatek rende più chiaro il controllo del flusso e i collegamenti della guida bash sono eccellenti

La risposta di @muru ha una buona spiegazione del perché non usare set -e se si desidera che vengano generati messaggi di errore personalizzati con alternative all'utilizzo di perl e trap, che ritengo sia un modo più robusto e mi vedo usarlo dal mio secondo script bash in poi!


Per quanto ne so, esce dal termine della sceneggiatura.
Pantera,

Risposte:


10

Probabilmente vuoi (come sottolineato da Steeldriver)

true || { echo "This shouldn't print" && exit; }

Altrimenti la tua sceneggiatura sta leggendo un condizionale alla volta

a o b e quindi esci

Penso che tu voglia a o (b ed esci)?


4
In realtà, è necessario utilizzare { ... ; }(come suggerito da @steeldriver), altrimenti l' exitunica uscita dalla subshell e la shell padre continua l'esecuzione dello script.
Gordon Davisson,

14

Il problema è che || e && salta una sola stanza successiva di una catena di comando quando la condizione fallisce. Se scrivi una struttura a blocchi completa ha perfettamente senso. Quello che hai scritto diventa questo:

if ! true ; then
   echo "This shouldn't print"
else
   exit
fi

Quello che vuoi è questo:

if ! true ; then
   echo "This shouldn't print"
   exit
fi

Quando si utilizzano gli operatori condizionali di scelta rapida di Bash, è meglio evitare di mescolarli. La logica è molto più facile da capire mentre la scrivi e i tuoi lettori apprezzeranno il tuo buon stile.


2
Sì, a mio avviso, questo è molto più di come dovrebbe essere scritto il condizionamento in bash
derHugo,

@takatakatek Questo rende più chiaro il motivo per cui fallisce nel mio caso. Sono d'accordo che la logica è chiara in questo, ma non è la ragione per raggruppare le condizioni usando && e || è evitare di esprimerli usando dichiarazioni condizionali?
Kosol,

@kosol Sì, && e || combinare due cose: testare lo stato di uscita del comando precedente e specificare un singolo comando (o gruppo di comandi) da eseguire (per &&) o da saltare (per ||). Possono essere utili per casi molto semplici, ma non possono sostituire i if ... then ... elif ... else ... fiblocchi completamente espressi . Sospetto che potresti non essere consapevole del fatto che Bash non ha veri tipi booleani visti in linguaggi più sofisticati. Se lo stato di uscita di un comando è 0 (zero), Bash lo considera come vero / successo . Se lo stato di uscita è diverso da zero, Bash lo considera falso / non riuscito .
Takatakatek,

7

Il modo più semplice di fallire in caso di errore è usare l' -eopzione di bash ( set -eo /bin/bash -enello shebang). Tuttavia, ciò non semplifica l'invio di messaggi di errore personalizzati. Ci sono un paio di idiomi che potrebbero renderlo più semplice:

die à la Perl

Perl ha un diecomando molto conveniente che stampa un messaggio su stderr e solleva un'eccezione, che di solito porta alla chiusura dello script. Puoi emularlo:

die () {
  ret=$?
  print "%s\n" "$@" >&2
  exit "$ret"
}

false || die "Obvious error because its false on left"
true || die "This shouldn't print"

trap ERR

Il trap <command>comando può essere utilizzato per eseguire un comando quando viene ricevuto un segnale, o quando si esce dallo script ( trap ... EXIT) o quando un comando restituisce un errore ( trap ... ERR). Quindi qualcosa del tipo:

trap 'ret=$?; printf "%s\n" "$ERR_MSG" >&2; exit "$ret"' ERR

Poi:

ERR_MSG="Obvious error because its false here"
false
ERR_MSG="This shouldn't print"
true

In entrambi i casi, suggerirei di usare almeno exit 1, per indicare che lo script non è riuscito . Una pianura exitutilizzerà lo stato di uscita del comando precedente, che in questi casi sarebbe il comando echoo printf, che di solito avrebbe successo. Salvare lo stato di uscita del comando non riuscito come ho fatto qui sarebbe un piacere.


6

Potresti provare a sperimentare un po 'con l'avvio dello script

#!/bin/bash -e

-E assicura che lo script esca nel momento in cui qualcosa ritorna falso. È quindi possibile evitare un errore specifico consomething || true

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.