프로세스 종료 시 기본 종료 코드는 무엇입니까?

프로세스 종료 시 기본 종료 코드는 무엇입니까?

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보다 크지 않도록 보장하여 달성됩니다.$?129exit(129)1HUP$?

    $ 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$statuscsh$?

  • rc: 종료 상태도 마찬가지지만 신호에 의해 종료되면 변수 에는 숫자 대신 $status신호 이름(예: sigterm코어 가 생성된 경우)이 포함되며 이는 이 쉘의 좋은 디자인에 대한 또 다른 증거입니다.sigill+core

  • es. 종료 상태는 변수가 아닙니다. 관심이 있으시면 다음 명령을 실행하십시오.

     status = <={cmd}
    

숫자나 이와 sigterm유사한 sigsegv+core것을 반환합니다 rc.

아마도 완전성을 위해 마지막 파이프라인 구성요소의 종료 상태를 포함하는 zsh's $pipestatusbash' 배열을 언급해야 할 것입니다 .$PIPESTATUS

그리고 완벽함을 위해 셸 함수와 소스 파일의 경우 기본적으로 함수는 마지막 명령 실행의 종료 상태를 반환하지만 반환 상태는 내장 함수를 사용하여 명시적으로 설정할 수도 있습니다 return. 여기에는 몇 가지 차이점이 있습니다.

  • bash그리고 mksh(R41 이후,회귀 변화는 분명히 의도적으로 도입되었습니다.)은 숫자(양수 또는 음수)를 8자리로 자릅니다. 예를 들어 , 255 return 1234로 설정됩니다 .$?210return -- -1$?
  • zsh그리고 pdksh(그리고 Except 의 파생물 mksh) 부호 있는 32비트 십진 정수(-2 31 ~ 2 31 -1)를 허용합니다(그리고 숫자를 32비트로 자릅니다).
  • ash0과 2 31yash -1 사이의 양의 정수를 허용 하고 그 안의 모든 숫자에 대해 오류를 반환합니다.
  • ksh93return 0있는 그대로 설정 하고 return 320다른 경우에는 8비트로 자릅니다. $?앞서 언급했듯이 256에서 320 사이의 숫자를 반환하면 ksh종료 시 자살을 초래할 수 있습니다.
  • rc목록도 포함 하여 es무엇이든 반환할 수 있습니다.

또한 일부 쉘은 특수 값 $?/를 사용하여 프로세스 종료 상태 가 $status아닌 일부 오류 조건을 보고합니다 .127126명령어를 찾을수 없음또는시행 불가능(또는 소스 파일의 구문 오류)...

답변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년이 지나면 모든 운영 체제가 곧 이를 올바르게 지원할 수 있기를 바랍니다.

관련 정보