다음을 고려하세요:
#!/bin/bash
trap 'echo $?' INT
kill -INT $$
산출:0
여기서 나는 130
내 시스템을 기대합니다. 물론 내가 a를 했다면 Ctrl + C
나는 130
.
HUP
또는 같은 다른 신호에서도 마찬가지입니다 TERM
. trap
많은 신호를 포착하는 설정이 있는 경우 핸들러가 호출된 신호에 대한 올바른 오류 코드로 종료할 수 없기 때문에 이 동작이 놀랍습니다 .
#!/bin/dash
exit_abrupt() {
exit_code=$?
echo "Encountered an error, cleaning up..." >&2
# *clean up*
exit "$exit_code" # This will return 0!
}
trap exit_abrupt HUP INT TERM
kill -HUP $$
Bash, Dash 및 ZSH를 테스트했는데 모두 이러한 동작을 나타냈습니다. 이것이 크로스 쉘이 작동하는 방식입니까? POSIX에 의해 문서화되어 있습니까(누군가 나에게 문서를 알려줄 수 있습니까)? 셸에서 실행하기 위한 올바른 종료 코드를 어떻게 알 수 있나요?
최고POSIX 문서내가 읽은 내용은 다음과 같습니다.
"$"의 값은 무엇입니까? 트랩 작업의 완료는 트랩이 호출되기 전의 값이어야 합니다.
나에게는 모든 경우에 신호가 전달되어야 하는 것처럼 들리지만 그렇지 않으므로 뭔가 빠졌을 것입니다...
답변1
$?
마지막 명령 실행 및 대기의 종료 상태가 포함됩니다. 다음에서 찾을 수 있습니다:
$ bash -c 'trap "echo \$?" INT; sleep 10; exit'
^C130
130은 ^C sleep
에서 SIGINT를 수신 bash
하고 bash가 반환 후 핸들러를 실행하고 명령 sleep
의 종료 상태를 인쇄했기 때문에 보고되었습니다.sleep
존재하다:
$ bash -c 'trap "echo \$?" INT; kill -s INT "$$"; exit'
0
kill
SIGINT 핸들러를 호출하기 전에 bash가 마지막으로 실행한 명령인 명령의 종료 상태를 얻을 수 있습니다 .
$ bash -c 'trap "echo \$?" INT; (trap "" INT; sleep 3; exit 123); exit'
^C123
sleep
SIGINT를 무시하면 Ctrl+를 누른 후에도 C실행 중인 서브셸이 반환될 때까지 기다려야 하며 sleep
, 이때 핸들러는 서브셸의 종료 상태(123)를 인쇄합니다.
여러 신호에 대해 동일한 처리기를 설치하려면 신호를 처리기에 전달할 수 있습니다.
handler() {
local signal="$1"
echo "I got $signal signal"
}
for signal in INT HUP TERM QUIT; do
trap "handler $signal" "$signal"
done
그건 그렇고, 당신은 찾을 수 있습니다:
bash -c '(trap "" INT; sleep 3; exit 123); exit'
Ctrl+ 로 중단 하려고 해도 c종료 상태 123으로 종료되는데, 이는 실제로 bash의 설계입니다. 자세한 내용은 다음을 방문하세요.터미널에 ctrl-c를 입력할 때 포그라운드 작업이 완료되기 전에 종료되지 않는 이유는 무엇입니까?
답변2
EXIT
누군가가 필요할 경우를 대비하여 항상 올바른 종료 상태를 전달하면서 트랩을 치명적인 신호 트랩(키 입력을 통해 수신하든 쉘 프로세스로 전송된 신호이든)과 결합하기 위한 최종 솔루션은 다음과 같습니다.
#!/bin/sh
set -e
# https://unix.stackexchange.com/questions/752570/why-does-trap-passthough-zero-instead-of-the-signal-the-process-was-killed-wit
handle_exit() {
exit_code=$?
signal="$1"
if [ "$exit_code" != 0 ] || [ "$signal" ]; then
echo "\nProgram was exited abruptly!" >&2
fi
# Or do clean up here...
if [ "$exit_code" != 0 ]; then
trap -- - EXIT
exit "$exit_code"
elif [ "$signal" ]; then
trap -- - "$signal"
kill -s "$signal" -- $$
fi
}
# POSIX sh doesn't include signals in its EXIT trap so list them ourselves
# SIG prefixes removed for POSIX sh compatibility
for signal in HUP INT TERM; do
# shellcheck disable=SC2064
trap "handle_exit $signal" "$signal"
done
trap handle_exit EXIT
# Your code starts here...
이는 리터럴 ( ) 을 트리거하면 트랩이 트랩보다 먼저 트리거되기 trap -- - EXIT
때문에 필요합니다 . 이 특별한 경우(리터럴로 인해 ) 도 로 설정됩니다 . 따라서 핸들러가 두 번 트리거되는 것을 방지하기 위해 분기에서 트랩을 제거합니다 . 또한 스택 오버플로가 발생할 때까지 핸들러를 영원히 재귀적으로 호출하지 마십시오.INT
Ctrl + C
INT
EXIT
Ctrl + C
$exit_code
130
EXIT
if
trap -- - "$signal"
모든 쉘(Posh 포함)에서는 매력처럼 작동합니다.