it-swarm.com.de

Wie finde ich die Zeilennummer in Bash, wenn ein Fehler aufgetreten ist?

Wie finden Sie die Zeilennummer in Bash, bei der ein Fehler aufgetreten ist?

Beispiel

Ich erstelle das folgende einfache Skript mit Zeilennummern, um zu erklären, was wir brauchen. Das Skript kopiert Dateien von

cp $file1 $file2
cp $file3 $file4

Wenn einer der Befehle cp fehlschlägt, wird die Funktion mit exit 1 beendet. Wir möchten der Funktion die Möglichkeit hinzufügen, den Fehler auch mit der Zeilennummer (z. B. 8 oder 12) zu drucken.

Ist das möglich?

Beispielskript

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
23
yael

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"

Dies funktioniert, indem ERR abgefangen und dann die Funktion failure() mit der aktuellen ausgeführten Zeilennummer + dem Befehl bash aufgerufen wird.

Beispiel

Hier habe ich nicht darauf geachtet, die Dateien f1, f2, f3 Oder f4 Zu erstellen. 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 ausgeführte Zeilennummer plus Befehl.

32
slm

Zusätzlich zu LINENO, das die aktuelle Zeilennummer enthält, gibt es das BASH_LINENO und FUNCNAME (und BASH_SOURCE) Arrays, die die Funktionsnamen und Zeilennummern enthalten, von denen sie aufgerufen werden.

Sie könnten also so etwas tun:

#!/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

Laufen, das würde drucken

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

Wenn du benutzt set -e, oder trap ... ERR Um Fehler automatisch zu erkennen, beachten Sie, dass sie einige Einschränkungen aufweisen. Es ist auch schwieriger, eine Beschreibung der damaligen Funktionsweise des Skripts anzugeben (wie in Ihrem Beispiel), obwohl dies für einen normalen Benutzer möglicherweise nützlicher ist als nur die Zeilennummer.

Siehe z. diese für die Probleme mit set -e und andere:

15
ilkkachu

Bash hat eine eingebaute Variable $LINENO, das in einer Anweisung durch die aktuelle Zeilennummer ersetzt wird, damit Sie dies tun können

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

Sie können auch versuchen, trap ... ERR wird ausgeführt, wenn ein Befehl fehlschlägt (wenn das Ergebnis nicht getestet wird). Z.B:

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

Wenn dann ein Befehl wie cp $file1 $file2 schlägt fehl, Sie erhalten die Fehlermeldung mit der Zeilennummer und einem Exit. Sie finden den fehlerhaften Befehl auch in der Variablen $BASH_COMMAND (obwohl keine Weiterleitungen usw.).

14
meuh