SIGINT
프로세스가 처리 가능한 신호(예: 또는 )에 의해 종료되었지만 SIGTERM
신호를 처리하지 않는 경우 프로세스의 종료 코드는 무엇입니까?
이와 같이 처리할 수 없는 신호를 처리하려면 어떻게 해야 합니까 SIGKILL
?
내가 아는 한, 프로세스를 종료하면 SIGINT
종료 코드가 발생할 수 있지만 130
이것이 커널 또는 셸 구현에 따라 달라지나요?
$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130
다른 신호를 테스트하는 방법을 잘 모르겠습니다...
$ ./myScript &
$ killall myScript
$ echo $?
0 # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0 # same problem
답변1
프로세스는 정수 인수를 사용하여 _exit()
시스템 호출(Linux의 경우 리소스 참조 )을 호출하여 exit_group()
상위 프로세스에 종료 코드를 보고할 수 있습니다. 정수이지만 최하위 비트 8개만 상위 비트에 사용할 수 있습니다(예외는 다음과 같습니다).waitid()
해당 코드를 검색하려면 상위에서 SIGCHLD 또는 핸들러를 사용하십시오., Linux에서는 그렇지 않지만).
부모는 일반적으로 다음을 수행 wait()
하거나 waitpid()
얻습니다.상태그들의 자식은 정수로 표시됩니다( waitid()
약간 다른 의미를 사용할 수도 있음).
Linux 및 대부분의 Unices에서 프로세스가 정상적으로 종료되면 프로세스의 비트 8~15상태번호에는 에 전달된 종료 코드가 포함됩니다 exit()
. 그렇지 않은 경우 최하위 7개 비트(0~6)에 신호 번호가 포함되며, 코어가 덤프된 경우 비트 7이 설정됩니다.
perl
예를 들어 $?
다음과 같이 설정된 숫자를 포함합니다 waitpid()
.
$ perl -e 'system q(kill $$); printf "%04x\n", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04x\n", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04x\n", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status
$?
Bourne과 같은 쉘은 또한 자신의 특수 매개변수에서 마지막 명령 실행의 종료 상태를 설정합니다. 그러나 반환된 숫자는 직접 포함되지 않지만 waitpid()
변환되어 쉘마다 다릅니다.
모든 쉘의 공통점은 프로세스가 정상적으로 종료되면 $?
종료 코드(전달된 숫자)의 가장 낮은 8비트를 포함한다는 것입니다.exit()
차이점은 프로세스가 신호에 의해 종료될 때입니다. POSIX에서는 모든 경우에 이 숫자가 128보다 커야 합니다. POSIX는 이 값이 무엇인지 지정하지 않습니다. 그러나 실제로 내가 아는 모든 Bourne과 같은 쉘에서는 가장 낮은 7비트에 $?
신호 번호가 포함됩니다. 그런데 n
신호번호는 어디에 있고,
ash, zsh, pdksh, bash, Bourne 쉘에서
$?
yes 이는 이러한 쉘에서 of 를128 + n
얻으면 프로세스가 종료되었거나 신호에 의해 종료되었기 때문인지 알 수 없음을 의미합니다 ( 대부분의 시스템에서). . 그러나 기본 원칙은 쉘이 자체적으로 종료될 때 기본적으로 마지막 종료 명령의 종료 상태를 반환한다는 것입니다. 일관된 종료 상태 는 255보다 크지 않도록 보장하여 달성됩니다.$?
129
exit(129)
1
HUP
$?
$ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"' bash: line 1: 16720 Terminated sh -c "kill \$\$" 8f # 128 + 15 $ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?" bash: line 1: 16726 Terminated sh -c "kill \$\$" 8f # here that 0x8f is from a exit(143) done by bash. Though it's # not from a killed process, that does tell us that probably # something was killed by a SIGTERM
ksh93
,$?
예256 + n
. 이는$?
의 값을 기준으로 종료된 프로세스와 종료되지 않은 프로세스를 구별할 수 있음을 의미합니다. 최신 버전은ksh
종료 시$?
255보다 크면 동일한 종료 상태를 상위 항목에 보고할 수 있도록 동일한 신호로 자체 종료됩니다. 이는 좋은 생각처럼 들리지만,ksh
코어 생성 신호에 의해 프로세스가 종료되면 추가 코어 덤프가 생성됩니다(다른 코어 덤프를 덮어쓸 수도 있음).$ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"' ksh: 16828: Terminated 10f # 256 + 15 $ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?" ksh: 16816: Illegal instruction(coredump) Illegal instruction(coredump) 104 # 256 + 15, ksh did indeed kill itself so as to report the same # exit status as sh. Older versions of `ksh93` would have returned # 4 instead.
오류가 있다고 말할 수도 있고 , 함수가 완료 되더라도
ksh93
오류 가 스스로 종료될 것입니다.$?
return 257
$ ksh -c 'f() { return "$1"; }; f 257; exit' zsh: hangup ksh -c 'f() { return "$1"; }; f 257; exit' # ksh kills itself with a SIGHUP so as to report a 257 exit status # to its parent
yash
.yash
타협이 제안됩니다. 그것은 반환합니다256 + 128 + n
. 이는 종료된 프로세스와 올바르게 종료된 프로세스를 구별할 수도 있음을 의미합니다. 종료 후에128 + n
는 자살하지 않고 그에 따른 부작용을 보고합니다 .$ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"' 18f # 256 + 128 + 15 $ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?" 8f # that's from a exit(143), yash was not killed
의 값에서 신호를 얻으려면 $?
이식 가능한 방법은 다음을 사용하는 것입니다 kill -l
.
$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM
(이식성을 위해 시그널 번호는 사용하지 말고 시그널 이름만 사용하세요)
베른이 아닌 전선에서:
csh
/ 상태가 in이라는 점을 제외하면 Bourne 쉘 과tcsh
동일 합니다 . ((ext)와의 호환성도 설정되어 있습니다 .)fish
$status
$?
zsh
$status
csh
$?
rc
: 종료 상태도 마찬가지지만 신호에 의해 종료되면 변수 에는 숫자 대신$status
신호 이름(예:sigterm
코어 가 생성된 경우)이 포함되며 이는 이 쉘의 좋은 디자인에 대한 또 다른 증거입니다.sigill+core
es
. 종료 상태는 변수가 아닙니다. 관심이 있으시면 다음 명령을 실행하십시오.status = <={cmd}
숫자나 이와 sigterm
유사한 sigsegv+core
것을 반환합니다 rc
.
아마도 완전성을 위해 마지막 파이프라인 구성요소의 종료 상태를 포함하는 zsh
's $pipestatus
및 bash
' 배열을 언급해야 할 것입니다 .$PIPESTATUS
그리고 완벽함을 위해 셸 함수와 소스 파일의 경우 기본적으로 함수는 마지막 명령 실행의 종료 상태를 반환하지만 반환 상태는 내장 함수를 사용하여 명시적으로 설정할 수도 있습니다 return
. 여기에는 몇 가지 차이점이 있습니다.
bash
그리고mksh
(R41 이후,회귀 변화는 분명히 의도적으로 도입되었습니다.)은 숫자(양수 또는 음수)를 8자리로 자릅니다. 예를 들어 , 255return 1234
로 설정됩니다 .$?
210
return -- -1
$?
zsh
그리고pdksh
(그리고 Except 의 파생물mksh
) 부호 있는 32비트 십진 정수(-2 31 ~ 2 31 -1)를 허용합니다(그리고 숫자를 32비트로 자릅니다).ash
0과 2 31yash
-1 사이의 양의 정수를 허용 하고 그 안의 모든 숫자에 대해 오류를 반환합니다.ksh93
return 0
있는 그대로 설정 하고return 320
다른 경우에는 8비트로 자릅니다.$?
앞서 언급했듯이 256에서 320 사이의 숫자를 반환하면ksh
종료 시 자살을 초래할 수 있습니다.rc
목록도 포함 하여es
무엇이든 반환할 수 있습니다.
또한 일부 쉘은 특수 값 $?
/를 사용하여 프로세스 종료 상태 가 $status
아닌 일부 오류 조건을 보고합니다 .127
126
명령어를 찾을수 없음또는시행 불가능(또는 소스 파일의 구문 오류)...
답변2
프로세스가 종료되면 운영 체제에 정수 값을 반환합니다. 대부분의 Unix 변형에서 이 값은 모듈로 256입니다. 즉, 낮은 비트를 제외한 모든 비트는 무시됩니다. 하위 프로세스의 상태는 16비트 정수를 통해 상위 프로세스로 반환됩니다.
- 비트 0-6(하위 7비트)은 프로세스를 종료하는 데 사용되는 신호 번호입니다. 프로세스가 정상적으로 종료되면 0이 됩니다.
- 프로세스가 신호에 의해 종료되고 코어를 덤프하는 경우 비트 7이 설정됩니다.
- 프로세스가 정상적으로 종료되면 비트 8-15는 프로세스의 종료 코드이고, 프로세스가 신호에 의해 종료되면 0입니다.
반환된 상태wait
시스템 호출 또는 그 형제 중 하나입니다. POSIX는 종료 상태 및 신호 번호의 정확한 인코딩을 지정하지 않습니다.
- 퇴실상태가 신호에 해당하는지, 정상퇴출에 해당하는지를 판단하는 방법;
- 프로세스가 정상적으로 종료되면 종료 코드에 액세스할 수 있습니다.
- 프로세스가 신호에 의해 종료된 경우 신호 번호에 액세스하는 방법입니다.
엄밀히 말하면 출구는 없어암호신호에 의해 프로세스가 종료되면 존재하는 것은 종료입니다.상태.
쉘 스크립트에서는명령의 종료 상태특수 변수를 통한 보고$?
. 이 변수는 종료 상태를 모호한 방식으로 인코딩합니다.
- 프로세스가 정상적으로 종료된 경우
$?
종료 상태입니다. - 프로세스가 신호에 의해 종료된 경우 이는
$?
대부분의 시스템에서 128에 신호 번호를 더한 값입니다. 이 경우 POSIX에서는$?
128보다 큰 숫자만 필요합니다. ksh93은 128 대신 256을 추가합니다. 나는 신호 번호에 상수를 추가하는 것 이외의 다른 작업을 수행하는 UNIX 변형을 본 적이 없습니다.
따라서 쉘 스크립트에서는 ksh93을 제외하고 명령이 신호에 의해 종료되었는지 또는 128보다 큰 상태 코드로 종료되었는지 확인할 수 없습니다. 프로그램이 128보다 큰 상태 코드로 종료되는 경우는 매우 드뭅니다. 부분적으로는 프로그래머가 $?
모호함으로 인해 종료하는 것을 피하기 때문입니다.
대부분의 Unix 변형에서 SIGINT는 신호 2이므로 $?
SIGINT에 의해 종료된 프로세스의 경우 SIGINT는 128+2=130입니다. SIGHUP은 129, SIGKILL은 137 등으로 표시됩니다.
답변3
그것은 쉘에 따라 다릅니다. bash(1)
매뉴얼 페이지 에서 ,쉘 문법부분,간단한 명령부분:
a의 반환 값간단한 명령[...] 128+입니다N명령이 신호에 의해 종료되는 경우N.
SIGINT
시스템의 신호 번호가 2이므로 Bash에서 실행될 때 반환 값은 130입니다 .
답변4
SVr4가 1989년에 waitid()를 도입했다고 언급하는 것이 적절한 것 같지만 지금까지 이를 사용하는 중요한 프로그램은 없는 것 같습니다. waitid()를 사용하면 전체 32비트를 종료() 코드에서 검색할 수 있습니다.
약 2개월 전에 나는 waitpid() 대신 waitid()를 사용하도록 Bourne Shell의 대기/작업 제어 부분을 다시 작성했습니다. 이는 0xFF로 종료 코드를 마스킹하는 제한을 제거하기 위해 수행됩니다.
waitid() 인터페이스는 1980년 UNOS의 cwait() 호출을 제외하면 이전 wait() 구현보다 훨씬 간단합니다.
다음 매뉴얼 페이지를 읽어보는 데 관심이 있을 수 있습니다.
http://schillix.sourceforge.net/man/man1/bosh.1.html
그리고 8페이지부터 시작되는 현재 "매개변수 대체" 섹션을 확인하세요.
waitid() 인터페이스에 새로운 변수 .sh.*가 도입되었습니다. 이 인터페이스는 더 이상 $?에 알려진 숫자에 대해 모호한 의미를 갖지 않습니다. 인터페이스가 더 쉬워집니다.
이 기능을 사용하려면 POSIX 호환 waitid()가 필요하므로 Mac OS 종료 코드에서 8비트만 얻을 수 있습니다.
즉, .sh.status는 숫자 종료 코드이고 .sh.code는 숫자 종료 이유입니다.
더 나은 이식성을 위해 "DUMPED"와 같은 종료 이유의 텍스트 버전을 나타내는 .sh.codename과 프로세스를 종료한 신호의 신호 이름을 나타내는 .sh.termsig가 있습니다.
더 나은 사용을 위해 프로그램을 전혀 시작할 수 없을 때 사용되는 "NOEXEC" 및 "NOTFOUND"라는 두 가지 종료 독립적 .sh.codename 값이 있습니다.
FreeBSD는 제가 보고한 지 20시간 이내에 waitid() 커널 버그를 수정했지만 Linux에서는 아직 수정을 시작하지 않았습니다. 이 기능이 POSIX에 도입된 지 26년이 지나면 모든 운영 체제가 곧 이를 올바르게 지원할 수 있기를 바랍니다.