SIGINT 및 유사한 이벤트를 포착할 때 종료 코드를 유지하시겠습니까?

SIGINT 및 유사한 이벤트를 포착할 때 종료 코드를 유지하시겠습니까?

설명된 대로 사용하는 경우 trap, 예를 들어http://linuxcommand.org/wss0160.php#trap종료하기 전에 ctrl-c(또는 유사)를 잡아서 정리한 다음 반환된 종료 코드를 변경하겠습니다.

이제 이는 실제 세계에 영향을 미치지 않을 수 있습니다(예: 종료 코드는 이식 가능하지 않고 그 이상은 항상 명확하지 않기 때문입니다.프로세스 종료 시 기본 종료 코드는 무엇입니까?) 하지만 이를 방지하고 스크립트를 중단시키는 기본 오류 코드를 반환할 수 있는 방법이 실제로 없는지 여전히 궁금합니다.

예(bash에서, 그러나 내 질문은 bash에만 해당되는 것으로 간주되어서는 안 됩니다):

#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _

산출:

$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT 
EXIT
$ echo $?
1

(POSIX와 더 호환되도록 제거하도록 편집되었습니다.)

(bash 스크립트로 만들기 위해 다시 편집했지만 내 질문은 쉘에만 국한되지 않습니다.)

휴대용 "SIGINT" 대신 트랩에 휴대용 "INT"를 사용하도록 편집되었습니다.

쓸모없는 중괄호를 제거하고 잠재적인 솔루션을 추가하도록 편집되었습니다.

고쳐 쓰다:

이제 일부 오류 코드를 종료하고 하드코딩하고 EXIT를 잡아서 문제를 해결했습니다. 오류 코드가 다르거나 EXIT 트랩이 불가능하므로 일부 시스템에서는 문제가 될 수 있지만 제 경우에는 이것으로 충분했습니다.

trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM

답변1

실제로 bash의 내부를 중단하는 것은 readbash가 실행 중인 명령을 중단하는 것과 약간 다른 것 같습니다. 일반적으로 , trap를 입력하면 $?이 값을 유지하고 동일한 값으로 종료할 수 있습니다.

trap 'rc=$?; echo $rc SIGINT; exit $rc' INT
trap 'rc=$?; echo $rc EXIT; exit $rc' EXIT

sleep 와 같은 명령이나 내장 명령을 실행하는 동안 스크립트가 중단되면 다음 과 wait같은 메시지가 표시됩니다.

130 SIGINT
130 EXIT

종료 코드는 130입니다. 그러나 0인 read -p것 같습니다 $?(어쨌든 내 bash 버전 4.3.42에서는).


내 버전의 변경 파일에 따라 신호 처리가 read진행 중일 수 있습니다... (/usr/share/doc/bash/CHANGES)

이 bash-4.3-alpha 버전과 이전 버전의 bash-4.2-release 간의 변경 사항입니다.

  1. 배쉬의 새로운 기능

    Posix 모드에서는 "읽기"가 캡처 신호에 의해 중단될 수 있습니다. 트랩 핸들러를 실행한 후 read는 128+signal을 반환하고 부분적으로 읽은 입력을 삭제합니다.

답변2

$?트랩 핸들러에 들어가면 일반적인 신호 종료 코드 중 하나를 사용할 수 있습니다.

sig_handler() {
    exit_status=$?  # Eg 130 for SIGINT, 128 + (2 == SIGINT)
    echo "Doing signal-specific up"
    exit "$exit_status"
}
trap sig_handler INT HUP TERM QUIT

별도의 EXIT 트랩이 있는 경우 동일한 접근 방식을 사용할 수 있습니다. 즉, 신호 처리기(있는 경우)에서 전달된 종료 상태를 즉시 지운 다음 저장된 종료 상태를 반환합니다.

답변3

단순히 일부 오류 코드를 반환하는 것만으로는 SIGINT 종료를 시뮬레이션하는 데 충분하지 않습니다. 지금까지 아무도 이것을 언급하지 않았다는 것에 놀랐습니다. 추가 자료:https://www.cons.org/cracauer/sigint.html

올바른 접근 방식은 다음과 같습니다.

for sig in EXIT ABRT HUP INT PIPE QUIT TERM; do
    trap "cleanup;
          [ $sig  = EXIT ] && normal_exit_only_cleanup;
          [ $sig != EXIT ] && trap - $sig EXIT && kill -s $sig $$
         " $sig
done

이는 Bash, Dash 및 zsh에서 작동합니다. 추가 이식성을 위해서는 디지털 신호 사양을 사용해야 합니다(반면에 zsh는 명령에 문자열 인수가 필요합니다 kill...)

또한 신호의 특별한 처리에 주의하십시오 EXIT. 이는 일부 쉘(예: Bash)이 모든 신호에 대해 트랩을 수행하기 때문입니다 EXIT(해당 신호에 정의될 수 있는 트랩 이후). 트랩을 재설정하면 EXIT이러한 일이 발생하지 않습니다.

"정상" 종료 시에만 코드를 실행합니다.

이 검사를 [ $sig = EXIT ]통해 코드는 정상적인(신호 없음) 종료에서만 실행될 수 있습니다. 하지만,모두신호에는 트랩이 있어야 하며, 마지막으로 트랩이 재설정됩니다 EXIT. normal_exit_only_cleanup존재하지 않는 신호에 대해서도 호출됩니다. 를 종료해도 실행됩니다 set -e. 이는 캡처 ERR(Dash에서는 지원되지 않음)하고 [ $sig = ERR ]실행하여 수행할 수 있습니다 kill.

Bash의 단순화된 버전

반면에 이 동작은 Bash에서는 간단히 다음을 수행할 수 있음을 의미합니다.

trap cleanup EXIT

정리 코드를 실행하고 종료 상태를 유지하세요.

편집됨

  • Bash의 "EXIT 캡처 모든" 동작에 대해 자세히 설명

  • 캡쳐할 수 없는 KILL 시그널 제거

  • 신호 이름에서 SIG 접두사 제거

  • 시도하지 마세요kill -s EXIT

  • set -e/ERR을 고려하세요 .

답변4

EXIT 핸들러를 변경하기만 하면 됩니다.~에귀하의 정리 처리기. 예는 다음과 같습니다.

#!/bin/bash
cleanup() {
    echo trapped exit
    trap 'exit 0' EXIT
}
trap cleanup EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. '

관련 정보