So lösen Sie einen Fehler mit dem Befehl "Trap" aus

13

Ich benutze Ubuntu 12.04.2. Ich versuche, den Befehl "trap" zu verwenden, um Fehler in meinem Shell-Skript zu erfassen, aber ich versuche auch, das Beenden von "Error" manuell auszulösen.

Ich habe Exit 1 ausprobiert, aber es wird kein "Fehler" -Signal ausgelöst.

#!/bin/bash

func()
{
    exit 1
}

trap "echo hi" INT TERM ERR
func

Sie sind sich nicht sicher, wie Sie das Beendigungssignal "Fehler" manuell auslösen sollen?

Waldclown
quelle

Antworten:

20

Der ERRTrap soll keinen Code ausführen, wenn die Shell selbst mit einem Fehlercode ungleich Null beendet wird, sondern wenn ein Befehl, der von dieser Shell ausgeführt wird, die nicht Teil einer Bedingung ist (wie in if cmd...oder cmd || ......), mit einem Fehlercode ungleich Null beendet wird Beendigungsstatus (die gleichen Bedingungen set -e, unter denen die Shell beendet wird).

Wenn Sie Code beim Beenden der Shell mit einem Exit-Status ungleich Null ausführen möchten, sollten Sie EXITstattdessen einen Trap hinzufügen und $?dort Folgendes überprüfen :

trap '[ "$?" -eq 0 ] || echo hi' EXIT

Beachten Sie jedoch, dass bei einem überfüllten Signal sowohl die Signal-Trap als auch die EXIT-Trap ausgeführt werden.

unset killed_by
trap 'killed_by=INT;exit' INT
trap 'killed_by=TERM;exit' TERM
trap '
  ret=$?
  if [ -n "$killed_by" ]; then
    echo >&2 "Ouch! Killed by $killed_by"
    exit 1
  elif [ "$ret" -ne 0 ]; then
    echo >&2 "Died with error code $ret"
  fi' EXIT

Oder um den Ausgangsstatus wie $((signum + 128))bei Signalen zu verwenden:

for sig in INT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig")))" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"' EXIT

Beachten Sie jedoch, dass das normale Beenden bei SIGINT oder SIGQUIT möglicherweise ärgerliche Nebenwirkungen hat, wenn Ihr übergeordneter Prozess eine Shell wie diese ist bash, die das Warten und die kooperative Beenden- Behandlung von Terminal-Interrupts implementiert . Vielleicht möchten Sie sich also mit demselben Signal umbringen, um Ihren Eltern mitzuteilen, dass Sie tatsächlich unterbrochen wurden, und dass sie in Betracht ziehen sollten, sich selbst zu beenden, wenn sie ein SIGINT / SIGQUIT erhalten haben.

unset killed_by
for sig in INT QUIT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig"))); killed_by=$sig" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"
  if [ -n "$killed_by" ]; then
    trap - "$killed_by" # reset handler
    # ulimit -c 0 # possibly disable core dumps
    kill -s "$killed_by" "$$"
  else
    exec "$ret"
  fi' EXIT

Wenn die ERRFalle ausgelöst werden soll, führen Sie einfach einen Befehl mit einem Exit-Status ungleich Null wie falseoder aus test.

Stéphane Chazelas
quelle
6

Verwenden Rückkehr, nicht Ausfahrt, den Status beim Verlassen einer Funktion zu setzen (wenn die Funktion fällt Durch ohne Rückkehr, der Status ist , dass die letzten Anweisung ausgeführt.) Wenn Sie ersetzen returnfür exitin der Frage des Beispiel, wird es funktionieren wie Ich denke, Sie haben es beabsichtigt: Die Falle wird auf dem ERR-Pseudosignal ausgelöst und 'hi' wird gedruckt. Versuchen Sie dies für zusätzliche Überlegungen:

#!/bin/bash

func()
{
    echo 'in func'
    return 99
    echo 'still in func'
}

trap 'echo "done"' EXIT
trap 'status=$?; echo "error status is $status"; trap - EXIT; exit $status' ERR
func
echo 'returned from func'

Sie können verschiedene Modifikationen ausprobieren, z. B. 0 zurückgeben, den ERR-Trap auskommentieren, den EXIT-Trap im ERR-Handler nicht aufheben, den ERR-Handler nicht verlassen oder die Rückgabe entfernen und falseals letzte Anweisung in func einfügen.

Sdenham
quelle