Come trovo il numero di riga in Bash quando si è verificato un errore?


21

Come si trova il numero di riga in Bash in cui si è verificato un errore?

Esempio

Creo il seguente semplice script con i numeri di riga per spiegare di cosa abbiamo bisogno. Lo script copierà i file da

cp $file1 $file2
cp $file3 $file4

Quando uno dei cpcomandi fallisce, la funzione termina con l' uscita 1 . Vogliamo aggiungere la possibilità alla funzione di stampare anche l'errore con il numero di riga (ad esempio 8 o 12).

È possibile?

Script di esempio

1 #!/bin/bash
2
3
4 function in_case_fail {
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6 }
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14


È possibile utilizzare set -xe / o set -vtracciare ciò che è stato eseguito. Non esattamente quello che hai chiesto, ma probabilmente sarà anche utile.
Rolf,

Risposte:


29

Invece di usare la tua funzione, userei questo metodo invece:

$ cat yael.bash
#!/bin/bash

set -eE -o functrace

file1=f1
file2=f2
file3=f3
file4=f4

failure() {
  local lineno=$1
  local msg=$2
  echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR

cp -- "$file1" "$file2"
cp -- "$file3" "$file4"

Funziona intercettando ERR e quindi chiamando la failure()funzione con l'attuale numero di riga + comando bash che è stato eseguito.

Esempio

Qui non ho preso alcuna cura per creare i file, f1, f2, f3, o f4. Quando eseguo lo script sopra:

$ ./yael.bash
cp: cannot stat f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"

Non riesce, riportando il numero di riga più il comando che è stato eseguito.


14

Oltre a LINENOcontenere il numero di riga corrente, ci sono gli array BASH_LINENOe FUNCNAME(e BASH_SOURCE) che contengono i nomi delle funzioni e i numeri di riga da cui vengono chiamati.

Quindi potresti fare qualcosa del genere:

#!/bin/bash

error() {
        printf "'%s' failed with exit code %d in function '%s' at line %d.\n" "${1-something}" "$?" "${FUNCNAME[1]}" "${BASH_LINENO[0]}"
}

foo() {
        ( exit   0 ) || error "this thing"
        ( exit 123 ) || error "that thing"
}

foo

In esecuzione che verrebbe stampato

'that thing' failed with exit code 123 in function 'foo' at line 9.

Se si utilizza set -eo trap ... ERRper rilevare automaticamente errori, tenere presente che presentano alcuni avvertimenti. È anche più difficile includere una descrizione di ciò che lo script stava facendo in quel momento (come hai fatto nell'esempio), sebbene ciò potrebbe essere più utile per un utente normale rispetto al solo numero di riga.

Vedi ad esempio questi per i problemi con set -ee altri:


13

Bash ha una variabile incorporata $LINENOche viene sostituita dal numero di riga corrente quando in un'istruzione, quindi puoi farlo

in_case_fail $? "at $LINENO: cp $file1 $file2"

Puoi anche provare a usare trap ... ERRquale viene eseguito quando un comando fallisce (se il risultato non viene testato). Per esempio:

trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR

Quindi se un comando come cp $file1 $file2fallisce otterrai il messaggio di errore con il numero di riga e un'uscita. Troverai anche il comando in errore nella variabile $BASH_COMMAND(sebbene non ci siano reindirizzamenti ecc.).

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.