Jak wyzwolić błąd za pomocą polecenia Pułapka

13

Używam Ubuntu 12.04.2. Próbuję użyć polecenia „trap”, aby przechwycić nieprawidłowe lub błędne skrypty powłoki, ale próbuję również ręcznie uruchomić wyjście „Błąd”.

Próbowałem wyjść 1, ale nie wyzwala sygnału „Błąd”.

#!/bin/bash

func()
{
    exit 1
}

trap "echo hi" INT TERM ERR
func

Nie wiesz, jak ręcznie wyzwolić sygnał wyjścia „Błąd”?

leśny klaun
źródło

Odpowiedzi:

20

ERRpułapka nie jest do uruchomienia kodu, gdy sama powłoka kończy pracę z niezerowym kodem błędu, ale kiedy każdy prowadzony przez polecenie tego płaszcza, który nie jest częścią stanu (jak w if cmd..., lub cmd || ......) wychodzi z niezerową status wyjścia (te same warunki, co powoduje set -ewyjście z powłoki).

Jeśli chcesz uruchomić kod po wyjściu z powłoki z niezerowym statusem wyjścia, powinieneś EXITzamiast tego dodać pułapkę i sprawdzić $?tam:

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

Zauważ jednak, że przy sygnale uwięzionym uruchamiana byłaby zarówno pułapka sygnału, jak i pułapka EXIT, więc możesz chcieć to zrobić w następujący sposób:

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

Lub użyć statusu wyjścia jak w $((signum + 128))przypadku sygnałów:

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

Zauważ jednak, że normalne wychodzenie z SIGINT lub SIGQUIT ma potencjalnie irytujące skutki uboczne, gdy proces nadrzędny jest podobny do powłoki, bashktóra implementuje obsługę oczekiwania i współpracy w przypadku przerwania terminala. Możesz więc upewnić się, że zabiłeś się tym samym sygnałem, aby zgłosić rodzicowi, że rzeczywiście zostałeś przerwany i że powinien również rozważyć wyjście z siebie, jeśli otrzyma SIGINT / SIGQUIT.

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

Jeśli chcesz uruchomić ERRpułapkę, po prostu uruchom polecenie z niezerowym statusem wyjścia, takim jak falselub test.

Stéphane Chazelas
źródło
6

Zastosowanie powrót, nie wyjście, aby ustawić status na wyjściu z funkcji (jeśli funkcja przypada przelotowe bez powrotu, status jest to, że od ostatniego sprawozdania wykonywane). Jeśli zastąpić returndla exitprzykładu pytaniem jest, to będzie działać jako Myślę, że zamierzałeś: pułapka zostanie uruchomiona na pseudo-sygnale ERR i zostanie wydrukowane „cześć”. Aby uzyskać dodatkowe uwagi, spróbuj tego:

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

Możesz wypróbować różne modyfikacje, takie jak zwracanie 0, komentowanie pułapki ERR, nie anulowanie pułapki WYJŚCIE w procedurze obsługi ERR, nie wychodzenie z procedury obsługi ERR lub usuwanie powrotu i wstawianie falsejako ostatniej instrukcji func.

sdenham
źródło