Anstatt Ihre Funktion zu verwenden, würde ich stattdessen diese Methode verwenden:
$ 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"
Das funktioniert, indem man ERR abfängt und dann failure()
aufruft Funktion mit der aktuellen Zeilennummer + dem ausgeführten Bash-Befehl.
Beispiel
Hier habe ich mich nicht um die Erstellung der Dateien gekümmert, f1
, f2
, f3
, oder f4
. Wenn ich das obige Skript ausführe:
$ ./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"
Es schlägt fehl und meldet die Zeilennummer plus den ausgeführten Befehl.
Zusätzlich zu LINENO
die aktuelle Zeilennummer enthalten, gibt es den BASH_LINENO
und FUNCNAME
(und BASH_SOURCE
) Arrays, die die Funktionsnamen und Zeilennummern enthalten, von denen sie aufgerufen werden.
Sie könnten also etwa so vorgehen:
#!/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
Wenn Sie das ausführen, wird gedruckt
'that thing' failed with exit code 123 in function 'foo' at line 9.
Wenn Sie set -e
verwenden , oder trap ... ERR
Um Fehler automatisch zu erkennen, beachten Sie, dass sie einige Einschränkungen haben. Es ist auch schwieriger, eine Beschreibung dessen einzufügen, was das Skript zu diesem Zeitpunkt tat (wie Sie es in Ihrem Beispiel getan haben), obwohl dies für einen normalen Benutzer nützlicher sein könnte als nur die Zeilennummer.
Siehe z.B. diese für die Probleme mit set -e
und andere:
- Warum funktioniert set -e nicht innerhalb von Subshells mit Klammern () gefolgt von einer ODER-Liste ||?
- bash -e wird beendet, wenn let oder expr 0 ergibt
- BashFAQ 105:Warum macht set -e (oder set -o errexit oder trap ERR) nicht das, was ich erwartet habe?
Bash hat eine eingebaute Variable $LINENO
die in einer Anweisung durch die aktuelle Zeilennummer ersetzt wird, also können Sie das tun
in_case_fail $? "at $LINENO: cp $file1 $file2"
Sie können es auch mit trap ... ERR
versuchen die ausgeführt wird, wenn ein Befehl fehlschlägt (wenn das Ergebnis nicht getestet wird). Beispiel:
trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR
Wenn dann ein Befehl wie cp $file1 $file2
schlägt fehl, erhalten Sie die Fehlermeldung mit der Zeilennummer und einem Exit. Sie finden den fehlerhaften Befehl auch in der Variablen $BASH_COMMAND
(allerdings keine Umleitungen etc.).