trap
trap ... INT TERM EXIT
청소 작업에 대한 많은 예. 하지만 세 가지 시그스펙을 모두 나열하는 것이 정말 필요한가요?
SIGNAL_SPEC가 EXIT (0) ARG인 경우 쉘을 종료할 때 실행됩니다.
SIGINT
나는 이것이 스크립트가 정상적으로 완료되었는지 또는 또는 를 받았기 때문에 적용된다고 생각합니다 SIGTERM
. 실험을 통해 내 믿음도 확증되었습니다.
$ cat ./trap-exit
#!/bin/bash
trap 'echo TRAP' EXIT
sleep 3
$ ./trap-exit & sleep 1; kill -INT %1
[1] 759
TRAP
[1]+ Interrupt ./trap-exit
$ ./trap-exit & sleep 1; kill -TERM %1
[1] 773
TRAP
[1]+ Terminated ./trap-exit
그러면 왜 그렇게 많은 예가 그것들을 모두 나열하는 걸까요 INT TERM EXIT
? 아니면 내가 뭔가를 놓치고 있는 걸까, EXIT
발바닥이 그걸 놓치는 경우가 있을까 ?
답변1
네, 조금 다릅니다.
EnterSIGINT
이 스크립트는 누르 거나 보내면 종료됩니다 SIGTERM
.
trap '' EXIT
echo ' --- press ENTER to close --- '
read response
다음을 누르면 스크립트가 종료됩니다 Enter.
trap '' EXIT INT TERM
echo ' --- press ENTER to close --- '
read response
*테스트 대상쉿,불다, 그리고지쉬. (더 이상 적용되지 않습니다.쉿트랩 실행 명령을 추가할 때)
그리고 @Shawn이 말한 내용은 다음과 같습니다.금연 건강 증진 협회그리고스프린트캡처 신호를 사용하지 마십시오 EXIT
.
EXIT
따라서 강력한 신호 처리를 위해서는 완전히 포착하는 것을 피하고 다음과 같은 것을 사용하는 것이 좋습니다 .
cleanup() {
echo "Cleaning stuff up..."
exit
}
trap cleanup INT TERM
echo ' --- press ENTER to close --- '
read var
cleanup
답변2
이것POSIX 사양EXIT 트랩이 실행되는 조건에 대한 설명은 많지 않으며 실행 시 환경이 어떤 모습이어야 하는지만 설명됩니다.
Busybox의 ash 쉘에서 트랩 종료 테스트는 SIGINT 또는 SIGTERM으로 인해 종료하기 전에 "TRAP"를 에코하지 않습니다. 이런 식으로 작동하지 않는 다른 쉘이 있다고 생각됩니다.
# /tmp/test.sh & sleep 1; kill -INT %1
#
[1]+ Interrupt /tmp/test.sh
#
#
# /tmp/test.sh & sleep 1; kill -TERM %1
#
[1]+ Terminated /tmp/test.sh
#
답변3
문제가 있으므로 마지막 답변을 개선하려면 다음을 수행하십시오.
# Our general exit handler
cleanup() {
err=$?
echo "Cleaning stuff up..."
trap '' EXIT INT TERM
exit $err
}
sig_cleanup() {
trap '' EXIT # some shells will call EXIT after the INT handler
false # sets $?
cleanup
}
trap cleanup EXIT
trap sig_cleanup INT QUIT TERM
위의 사항은 다음과 같습니다.
테스트할 때 INT 및 TERM 핸들러는 종료되지 않습니다. 오류를 처리한 다음 쉘이 종료 상태를 반환합니다(놀랍지 않습니다). 그래서 청소 후에는 반드시 종료를 하도록 하고, 신호가 있을 경우에는 항상 에러코드를 사용합니다(그 외 정상 종료의 경우에는 에러코드를 유지합니다).
Bash를 사용하면 INT 핸들러에서 종료하면 EXIT 핸들러도 호출하는 것 같아서 종료 핸들러를 풀고 직접 호출했습니다(동작에 관계없이 모든 쉘에서 작동함).
쉘 스크립트가 맨 아래에 도달하기 전에 종료할 수 있기 때문에 종료를 포착합니다. 구문 오류, -e 및 0이 아닌 반환 설정, 그냥 종료를 호출합니다. 알아내기 위해 쉘 스크립트에 의존할 수는 없습니다.
한번도 시도해 본 적이 없다면 SIGQUIT는 Ctrl-\입니다. 추가 코어 덤프를 제공합니다. 그래서 조금 흐릿하더라도 담아두는 것도 가치가 있다고 생각해요.
과거 경험에 따르면 나처럼 항상 Ctrl-C를 몇 번 누르는 경우 쉘 스크립트의 정리 부분을 중간에 잡을 수도 있으므로 작동할 수 있지만 항상 원하는 만큼 완벽하지는 않습니다. .
답변4
달성하려는 목표와 대상 쉘에 따라 다릅니다. bash
어쩌면 그냥 사용할 수도 있기 때문입니다 EXIT
. 하지만모든 껍질은 아닙니다EXIT
/에서 핸들러를 호출합니다 .SIGINT
SIGTERM
이를 위해 여러 신호에 대한 핸들러( trap '...' INT EXIT
)를 설정해 볼 수 있지만 여러 번 호출될 수 있습니다.
$ bash -c 'trap "echo trap" INT EXIT; sleep 3' & pid=$!; sleep 1; kill -INT $pid; wait
[1] 276923
trap
trap
[1]+ Done bash -c 'trap "echo trap" INT EXIT; sleep 3'
따라서 글을 쓸 때 이 점을 염두에 두거나 시도해 볼 수 있습니다.앞으로EXIT
모든 것을 핸들러 에게 맡기세요 :
$ bash -c 'trap "exit 123" INT; trap "echo EXIT \$?" EXIT; sleep 3' & pid=$!; sleep 1; kill -INT $pid; wait
[1] 286229
EXIT 123
[1]+ Exit 123 bash -c 'trap "exit 123" INT; trap "echo EXIT \$?" EXIT; sleep 3'
SIGINT
하지만 다음에 대한 핸들러를 구축하면킬 스크립트SIGINT
:
a.sh
:
trap 'exit 123' INT
trap 'echo EXIT $?; trap - INT; kill -INT $$' EXIT
sleep 3
$ bash h.sh & pid=$!; sleep 1; kill -INT $pid; wait $pid
[1] 236263
EXIT 123
[1]+ Interrupt bash h.sh
그리고 데비안 < 10 ( dash < 0.5.10
)스크립트를 종료하라는 신호(그렇다면)통과하지 못함.
내가 생각해낸 해결책은 다음과 같습니다.
set -eu
cleanup() {
echo "cleanup ($1)"
trap - INT TERM EXIT # avoid reexecuting handlers
if [ "$1" = 130 ]; then
kill -INT $$
elif [ "$1" = 143 ]; then
kill -TERM $$
else
exit "$1"
fi
}
trap 'cleanup 130' INT
trap 'cleanup 143' TERM
trap 'cleanup $?' EXIT
if [ "${1-}" = fail ]; then
no-such-command
fi
sleep 3
$ bash f.sh; echo $?
cleanup (0)
0
$ bash f.sh fail; echo $?
f.sh: line 20: no-such-command: command not found
cleanup (127)
127
$ bash f.sh & pid=$!; sleep 1; kill -INT $pid; wait $pid
[1] 282422
cleanup (130)
[1]+ Interrupt bash f.sh
$ bash f.sh & pid=$!; sleep 1; kill -TERM $pid; wait $pid
[1] 282458
cleanup (143)
[1]+ Terminated bash f.sh
테스트 대상:
bash
:5.1.8
- 대시:
0.5.10
,0.5.8
,0.5.7
- 알파인 리눅스 3.14 (
busybox
)