"Trap...INT TERM EXIT"가 정말 필요한가요?

"Trap...INT TERM EXIT"가 정말 필요한가요?

traptrap ... 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/에서 핸들러를 호출합니다 .SIGINTSIGTERM

이를 위해 여러 신호에 대한 핸들러( 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)

관련 정보