SIGINT 등을 잡을 때 종료 코드를 유지 하시겠습니까?


14

http://linuxcommand.org/wss0160.php#trap 에서 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

스크립트가 약간 이상하게 보입니다. read현재 코 프로세스에서 읽 도록 지시 trap cmd SIGINT하고 표준에서 사용해야한다고 말하는 것처럼 작동하지 않습니다 trap cmd INT.
schily

예, POSIX에서는 SIG 접두사가 없습니다.
phk

죄송하지만 "read -p"도 지원되지 않으므로 bash에 맞게 조정하겠습니다.
phk

@schily : "coprocess"의 의미를 모르겠습니다.
phk

Korn Shell 매뉴얼 페이지 read -p에는 현재 코 프로세스의 입력을 읽습니다.
schily

답변:


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. '

trap cleanup INT대신에 의미 했 trap cleanup EXIT습니까?
Jeff Schaller

나는 EXIT을 의미한다고 생각합니다. exit가 마지막으로 호출되었지만 완료되면 반환 0으로 종료하도록 트랩을 변경합니다. 신호 처리기가 재귀 적이라고 생각하지 않습니다.
rocky

좋아, 귀하의 예에서 나는 사용자가 ctrl-c를 통해 대화 형 스크립트를 종료하더라도 실제로 정리하기 위해 (SIG) INT를 전혀 포획하지 않습니다.
phk

@phk Ok. 나는 당신이 exit를 강제로 0으로 반환하는 방법에 대한 아이디어를 얻었지만 내가 모은 것이 문제라고 생각합니다. 트랩 EXIT 설정을 SIGINT가 호출하는 실제 정리 처리기 안에 넣도록 코드를 조정할 수 있다고 가정합니다.
rocky

@ rocky : 내 목표는 일반적으로 처리기가없는 종료 코드를 변경하지 않고 트랩 처리기를 갖는 것이 었습니다. 이제는 일반적으로 얻을 수있는 종료 코드를 반환 할 수는 있지만 문제는이 경우 정확한 종료 코드를 알지 못한다는 것입니다 (연결 된 스레드와 meuh의 게시물에서 볼 수 있듯이 매우 복잡합니다). 귀하의 게시물이 여전히 도움이되었지만 트랩 핸들러를 동적으로 재정의하는 것에 대해서는 생각하지 않았습니다.
phk

9

실제로 bash의 내부 인터럽트는 bash가 read실행하는 명령을 인터럽트하는 것과 약간 다릅니다. 일반적으로을 입력 trap하면 $?이 설정되어 있으며 동일한 값으로 유지하고 종료 할 수 있습니다.

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

같은 명령을 실행할 때 스크립트가 중단 된 경우 sleep 또는 같은 심지어 내장을 wait, 당신은 볼 것이다

130 SIGINT
130 EXIT

그리고 종료 코드를 위해, 그러나 130 인 read -p것 같다, $?(어쨌든 bash는 4.3.42의 내 버전) 0입니다.


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

이 버전 bash-4.3-alpha와 이전 버전 bash-4.2-release 사이의 변경 사항.

  1. 배쉬의 새로운 기능

    아르 자형. Posix 모드에있을 때 트랩 된 신호에 의해 '판독'이 중단 될 수 있습니다. 트랩 처리기를 실행 한 후 읽기는 128+ 신호를 반환하고 부분적으로 읽은 입력을 버립니다.


네, 정말 이상합니다. bash 4.3.42 (cygwin 아래)의 대화 형 쉘에서는 130이며 스크립트 및 POSIX 모드에있을 때 같은 쉘 아래에 0이 있거나 차이가 없습니다. 그러나 대시와 비지 박스에서는 항상 1입니다.
phk

나는 종료되지 않는 트랩으로 POSIX 모드를 시도하고 readCHANGES 파일 (내 답변에 추가됨)에 명시된 것처럼를 다시 시작합니다 . 따라서 진행중인 작업 일 수 있습니다.
meuh

종료 코드 130은 100 % 이식 불가능합니다. Bourne Shell은 128 + signo신호의 종료 코드로 사용하지만 ksh93은을 사용합니다 256 + signo. POSIX의 말 : 128 이상 ....
schily

@schily 원래 게시물에 링크 된 스레드 ( unix.stackexchange.com/questions/99112 )에 명시된 바와 같이 True 입니다.
phk

6

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

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 트랩이있는 경우 동일한 방법을 사용할 수 있습니다. 신호 처리기에서 전달 된 종료 상태 (있는 경우)를 즉시 정리 한 다음 저장된 종료 상태를 리턴하십시오.


이것은 대부분의 껍질에 적용됩니까? 아주 좋아요 localPOSIX는 아닙니다.
phk

1
편집했습니다. 이외의 테스트는하지 않았습니다 {ba,z}sh. AFAIK, 그것은 상관없이 할 수있는 최선입니다.
Tom Hale

이것은 대시에서 작동하지 않습니다 ( $?수신 된 신호가 무엇이든 1입니다).
MoonSweep

2

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에서 간단히 할 수 있음을 의미합니다

trap cleanup EXIT

정리 코드를 실행하고 종료 상태를 유지합니다.

편집

  • "EXIT가 모든 것을 포착"하는 정교한 Bash의 동작

  • 갇힐 수없는 KILL 신호 제거

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

  • 시도하지 마십시오 kill -s EXIT

  • set -e/ ERR을 고려


신호를 포착하는 프로그램이 신호를 수신했다는 사실을 보존하는 방식으로 종료해야한다는 일반적인 요구 사항은 없습니다. 예를 들어, 프로그램은 전송 SIGINT이 종료하는 방법 이라고 선언 할 수 있으며 오류없이 종료 된 경우 0으로 종료하거나 완전히 종료되지 않은 경우 다른 오류 코드로 종료하기로 결정할 수 있습니다. 적절한 사례 : top. 실행 top; echo $?한 다음 Ctrl-C를 누르십시오. 화면에 덤프 된 상태는 0입니다.
Louis

1
지적 해 주셔서 감사합니다. 그러나 포스터는 구체적으로 종료 코드 유지 에 대해 물었습니다 .
philipp2100
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.