GNU/Linux >> Linux Esercitazione >  >> Linux

Genera errore in uno script Bash

Ci sono un altro paio di modi con cui puoi affrontare questo problema. Supponendo che uno dei tuoi requisiti sia eseguire uno script/funzione di shell contenente alcuni comandi di shell e verificare se lo script è stato eseguito correttamente e generare errori in caso di errori.

I comandi della shell in genere si basano sui codici di uscita restituiti per far sapere alla shell se ha avuto successo o meno a causa di alcuni eventi imprevisti.

Quindi quello che vuoi fare rientra in queste due categorie

  • uscita in caso di errore
  • uscita e pulizia in caso di errore

A seconda di quale vuoi fare, ci sono opzioni di shell disponibili da usare. Per il primo caso, la shell fornisce un'opzione con set -e e per il secondo potresti fare un trap il EXIT

Dovrei usare exit nel mio script/funzione?

Usando exit generalmente migliora la leggibilità In alcune routine, una volta che si conosce la risposta, si desidera uscire immediatamente dalla routine chiamante. Se la routine è definita in modo tale da non richiedere ulteriori operazioni di pulizia una volta rilevato un errore, non uscire immediatamente significa che devi scrivere altro codice.

Quindi, nei casi in cui è necessario eseguire azioni di pulizia sullo script per rendere pulita la terminazione dello script, è preferibile non per usare exit .

Dovrei usare set -e per errore in uscita?

No!

set -e era un tentativo di aggiungere "rilevamento automatico degli errori" alla shell. Il suo obiettivo era far sì che la shell si interrompesse ogni volta che si verificava un errore, ma presenta molte potenziali insidie, ad esempio,

  • I comandi che fanno parte di un test if sono immuni. Nell'esempio, se ti aspetti che si rompa su test controlla la directory inesistente, non lo farebbe, passa alla condizione else

    set -e
    f() { test -d nosuchdir && echo no dir; }
    f
    echo survived
    
  • I comandi in una pipeline diversa dall'ultima sono immuni. Nell'esempio seguente, poiché viene considerato il codice di uscita del comando eseguito più di recente (all'estrema destra) ( cat ) e ha avuto successo. Ciò potrebbe essere evitato impostando il set -o pipefail opzione ma è ancora un avvertimento.

    set -e
    somecommand that fails | cat -
    echo survived 
    

Consigliato per l'uso - trap in uscita

Il verdetto è se vuoi essere in grado di gestire un errore invece di uscire alla cieca, invece di usare set -e , usa un trap sul ERR pseudo segnale.

Il ERR trap non è eseguire il codice quando la shell stessa esce con un codice di errore diverso da zero, ma quando qualsiasi comando eseguito da quella shell che non fa parte di una condizione (come in if cmd o cmd || ) esce con uno stato di uscita diverso da zero.

La pratica generale è che definiamo un gestore di trap per fornire ulteriori informazioni di debug su quale riga e cosa causa l'uscita. Ricorda il codice di uscita dell'ultimo comando che ha causato il ERR segnale sarebbe ancora disponibile a questo punto.

cleanup() {
    exitcode=$?
    printf 'error condition hit\n' 1>&2
    printf 'exit code returned: %s\n' "$exitcode"
    printf 'the command executing at the time of the error was: %s\n' "$BASH_COMMAND"
    printf 'command present on line: %d' "${BASH_LINENO[0]}"
    # Some more clean up code can be added here before exiting
    exit $exitcode
}

e usiamo semplicemente questo gestore come sotto in cima allo script che sta fallendo

trap cleanup ERR

Mettere insieme tutto questo su un semplice script che conteneva false alla riga 15, le informazioni che otterresti come

error condition hit
exit code returned: 1
the command executing at the time of the error was: false
command present on line: 15

Il trap fornisce anche opzioni indipendentemente dall'errore per eseguire la pulizia solo al completamento della shell (ad es. lo script della shell termina), al segnale EXIT . Puoi anche intrappolare più segnali contemporaneamente. L'elenco dei segnali supportati su cui eseguire il trap può essere trovato nella trap.1p - pagina di manuale di Linux

Un'altra cosa da notare sarebbe capire che nessuno dei metodi forniti funziona se hai a che fare con sotto-shell coinvolte, nel qual caso potresti dover aggiungere la tua gestione degli errori.

  • Su una sub-shell con set -e non funzionerebbe. Il false è limitato alla sub-shell e non viene mai propagato alla shell madre. Per eseguire la gestione degli errori qui, aggiungi la tua logica per eseguire (false) || false

    set -e
    (false)
    echo survived
    
  • Lo stesso accade con trap anche. La logica seguente non funzionerebbe per i motivi sopra menzionati.

    trap 'echo error' ERR
    (false)
    

Gestione degli errori di base

Se il tuo test case runner restituisce un codice diverso da zero per i test falliti, puoi semplicemente scrivere:

test_handler test_case_x; test_result=$?
if ((test_result != 0)); then
  printf '%s\n' "Test case x failed" >&2  # write error message to stderr
  exit 1                                  # or exit $test_result
fi

O anche più breve:

if ! test_handler test_case_x; then
  printf '%s\n' "Test case x failed" >&2
  exit 1
fi

O il più breve:

test_handler test_case_x || { printf '%s\n' "Test case x failed" >&2; exit 1; }

Per uscire con il codice di uscita di test_handler:

test_handler test_case_x || { ec=$?; printf '%s\n' "Test case x failed" >&2; exit $ec; }

Gestione avanzata degli errori

Se vuoi adottare un approccio più completo, puoi avere un gestore di errori:

exit_if_error() {
  local exit_code=$1
  shift
  [[ $exit_code ]] &&               # do nothing if no error code passed
    ((exit_code != 0)) && {         # do nothing if error code is 0
      printf 'ERROR: %s\n' "[email protected]" >&2 # we can use better logging here
      exit "$exit_code"             # we could also check to make sure
                                    # error code is numeric when passed
    }
}

quindi invocalo dopo aver eseguito il test case:

run_test_case test_case_x
exit_if_error $? "Test case x failed"

o

run_test_case test_case_x || exit_if_error $? "Test case x failed"

I vantaggi di avere un gestore di errori come exit_if_error sono:

  • possiamo standardizzare tutta la logica di gestione degli errori come la registrazione, la stampa di una traccia dello stack, la notifica, la pulizia ecc., in un unico posto
  • facendo in modo che il gestore degli errori ottenga il codice di errore come argomento, possiamo risparmiare il chiamante dalla confusione di if blocchi che testano i codici di uscita per gli errori
  • se abbiamo un gestore di segnale (usando trap), possiamo invocare il gestore degli errori da lì

Libreria di gestione degli errori e registrazione

Ecco un'implementazione completa della gestione e registrazione degli errori:

https://github.com/codeforester/base/blob/master/lib/stdlib.sh

Post correlati

  • Gestione degli errori in Bash
  • Il comando integrato 'caller' su Bash Hackers Wiki
  • Esistono codici di stato di uscita standard in Linux?
  • BashFAQ/105 - Perché set -e (o set -o errexit o trap ERR) non fa quello che mi aspettavo?
  • Equivalente di __FILE__ , __LINE__ in Basch
  • C'è un comando TRY CATCH in Bash
  • Per aggiungere una traccia dello stack al gestore degli errori, potresti dare un'occhiata a questo post:Traccia dei programmi eseguiti chiamati da uno script Bash
  • Ignorare errori specifici in uno script di shell
  • Rilevamento di codici di errore in una shell pipe
  • Come gestisco la verbosità dei log all'interno di uno script di shell?
  • Come registrare il nome della funzione e il numero di riga in Bash?
  • Le parentesi quadre doppie [[ ]] sono preferibili alle parentesi quadre singole [ ] in Bash?

Ciò dipende da dove si desidera memorizzare il messaggio di errore.

Puoi fare quanto segue:

echo "Error!" > logfile.log
exit 125

O il seguente:

echo "Error!" 1>&2
exit 64

Quando sollevi un'eccezione interrompi l'esecuzione del programma.

Puoi anche usare qualcosa come exit xxx dove xxx è il codice di errore che potresti voler restituire al sistema operativo (da 0 a 255). Qui 125 e 64 sono solo codici casuali con cui puoi uscire. Quando devi indicare al sistema operativo che il programma si è arrestato in modo anomalo (ad es. si è verificato un errore), devi passare un codice di uscita diverso da zero a exit .

Come ha sottolineato @chepner, puoi fare exit 1 , che indicherà un errore non specificato .


Linux
  1. Come eseguire il debug di uno script Bash?

  2. Perché lo script Bash non si chiude dopo l'esecuzione?

  3. Esegue lo script bash dall'URL

  4. basename con spazi in uno script bash?

  5. Corrispondenza del modello di script Bash

Comando di uscita Bash e codici di uscita

35 Esempi di script Bash

Scopri la gestione degli errori di Bash con l'esempio

Come eseguire uno script Bash

alternative --config java bash script

Cosa significa set -e in uno script bash?