Piuttosto che usare la tua funzione, userei invece questo metodo:
$ 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 intrappolando su ERR e quindi chiamando failure()
funzione con il numero di riga corrente + il comando bash che è stato eseguito.
Esempio
Qui non mi sono preoccupato di creare i file, f1
, f2
, f3
o f4
. Quando eseguo lo script precedente:
$ ./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"
Fallisce, riportando il numero di riga più il comando che è stato eseguito.
Oltre a LINENO
contenente il numero di riga corrente, ci sono i BASH_LINENO
e 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
L'esecuzione verrebbe stampata
'that thing' failed with exit code 123 in function 'foo' at line 9.
Se usi set -e
o trap ... ERR
per rilevare automaticamente gli errori, tieni presente che hanno alcuni avvertimenti. È anche più difficile includere una descrizione di ciò che lo script stava facendo in quel momento (come hai fatto nel tuo esempio), anche se potrebbe essere più utile per un utente normale rispetto al semplice numero di riga.
Vedi ad es. questi per i problemi con set -e
e altri:
- Perché set -e non funziona all'interno di subshell con parentesi () seguite da un elenco OR ||?
- bash -e esce quando let o expr restituisce 0
- BashFAQ 105:Perché set -e (o set -o errexit o trap ERR) non fa quello che mi aspettavo?
Bash ha una variabile incorporata $LINENO
che viene sostituito dal numero di riga corrente in un'istruzione, quindi puoi farlo
in_case_fail $? "at $LINENO: cp $file1 $file2"
Puoi anche provare a usare trap ... ERR
che viene eseguito quando un comando fallisce (se il risultato non è testato). Ad esempio:
trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR
Quindi se un comando come cp $file1 $file2
fallisce si otterrà 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.).