"트랩… INT TERM EXIT"가 정말로 필요합니까?


63

정리 작업 에 trap사용 trap ... INT TERM EXIT하기위한 많은 예 . 그러나 세 sigspec을 모두 나열해야합니까?

매뉴얼은 말합니다 :

SIGNAL_SPEC이 EXIT (0) 인 경우 ARG는 쉘 종료시 실행됩니다.

이는 내가 믿는 스크립트가 정상적으로 완료하거나 수신하기 때문에 완료 여부를 적용 SIGINTSIGTERM. 실험은 또한 나의 믿음을 확인시켜줍니다 :

$ 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놓치고 발바닥 이 그리워지는 경우가 있습니까?


3
또한 INT TERM EXIT정리 코드 와 같은 사양을 사용 하면 SIGTERM또는 SIGINT수신 시 두 번 실행됩니다 .
maxschlepzig

답변:


19

POSIX 사양은 단지 환경이 실행될 때 같이해야 할 일에 대해, 종료 (EXIT) 트랩을 실행 결과 조건에 대해 많은 말을하지 않습니다.

Busybox의 애쉬 쉘에서 트랩 종료 테스트는 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
dash또한 EXIT받을 때 덫에 걸리지 않습니다 SIGINT/SIGTERM.
maxschlepzig

4
zsh또한 신호와 일치 bash하는 유일한 쉘일 것 입니다 EXIT.
maxschlepzig

@maxschlepzig는 zsh에 트랩을하지 않습니다 EXIT그것을받을 때 INT,하지만받을 때 그렇습니다 TERM. 편집 : 나는 이것이 얼마나 오래된 것을 알았습니다 ...
JoL

27

예, 차이가 있습니다.

이 스크립트는 누를 때 종료됩니다 Enter, 또는 보내 SIGINT거나 SIGTERM:

trap '' EXIT
echo ' --- press ENTER to close --- '
read response

이 스크립트는 다음을 누르면 종료됩니다 Enter.

trap '' EXIT INT TERM
echo ' --- press ENTER to close --- '
read response

* sh , BashZsh 에서 테스트되었습니다 . ( 트랩 실행 명령을 추가 할 때 sh 에서 더 이상 작동하지 않음 )


@Shawn이 말한 내용도 있습니다 : AshDash 는로 신호를 포착하지 않습니다 EXIT.

따라서 신호를 강력하게 처리하려면 트래핑을 피하고 EXIT다음과 같이 사용하는 것이 가장 좋습니다 .

cleanup() {
    echo "Cleaning stuff up..."
    exit
}

trap cleanup INT TERM
echo ' --- press ENTER to close --- '
read var
cleanup

1
정리 솔루션은 옳은 일을합니다-매우 우아합니다! mktemp호출 이있는 bash 스크립트의 관용구가되었습니다 .
Bjoern Dahlgren

2
그게 exit필요한 가요 cleanup?
jarno

3
코드에 쉘 스크립트 오류가있어 조기에 종료되는 경우에는 작동하지 않습니다.
ijw

2
@ijw : Bash와 Ksh에서는이 ERR를 처리하기 위해 덫 을 놓을 수 있지만 이식성이 없습니다 .
Zaz

5
이 솔루션은 다른 쉘이 호출 할 때 강력하지 않습니다. 협업 종료 대기를 처리하지 않습니다 . 당신이 원하는 것 trap - INT TERM; kill -2 $$이 조기에 종료 부모 쉘에게, 정리의 마지막 줄에있다. 부모 쉘 foobar.sh가 스크립트 (foo.sh)를 호출 한 다음 bar.sh를 호출하면 INT / TERM이 foo.sh로 전송되는 경우 bar.sh가 실행되는 것을 원하지 않습니다. trap cleanup EXIT이 전파를 자동으로 처리하므로 IMO가 가장 강력합니다. 또한 cleanup스크립트가 끝날 때 전화 할 필요가 없음을 의미합니다 .
Nicholas Pipitone

12

문제가 있기 때문에 마지막 답변을 수정하십시오.

# 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 처리기가 호출되므로 종료 처리기를 언 트랩하고 직접 호출합니다 (동작에 관계없이 모든 셸에서 작동 함).

쉘 스크립트가 맨 아래 구문 오류, set -e 및 0이 아닌 리턴에 도달하기 전에 exit를 호출하기 때문에 exit를 트랩합니다. 당신은 바닥에 닿는 쉘 스크립트에 의존 할 수 없습니다.

시도하지 않은 경우 SIGQUIT는 Ctrl- \입니다. 보너스 코어 덤프를 얻습니다. 조금 애매하지만 트래핑 할 가치가 있다고 생각합니다.

과거의 경험에 따르면 (나와 같이) 항상 Ctrl-C를 여러 번 누르면 쉘 스크립트의 정리 부분을 반쯤 잡아낼 수 있기 때문에 원하는대로 완벽하게 작동하지는 않습니다.


2
발신자는 어떤 신호가 종료를 유발했는지에 상관없이 종료 코드로 1을 얻습니다. 그러나 발신자는 trap130을, SIGINT는 143을, SIGTERM은 143을 얻습니다. 따라서 올바른 종료 코드를 캡처하고 전달합니다 sig_cleanup() { err=$?; trap '' EXIT; (exit $err); cleanup; }.
musiphil

2
trap '' EXIT INT TERM정리 기능 의 목적을 명확히 할 수 있습니까 ? 마지막 단락에서 언급 한 우발적 인 사용자 정리 정리를 방지하기위한 것입니까? EXIT중복 되지 않습니까?
Six
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.