"130으로 종료하는 것이 SIGINT로 죽는 것과 다른 이유는 무엇입니까?"

"130으로 종료하는 것이 SIGINT로 죽는 것과 다른 이유는 무엇입니까?"

스테판 차젤라스의 답장https://unix.stackexchange.com/a/230568

이상적으로는 SIGINT에서 사망했음을 부모에게 보고하고 싶습니다(따라서 다른 bash 스크립트인 경우 해당 bash 스크립트도 중단됩니다).130을 종료하는 것은 SIGINT로 죽는 것과는 다릅니다.(일부 쉘은 $?를 두 경우 모두 동일한 값으로 설정하지만) 일반적으로 SIGINT를 통해 사망을 보고하는 데 사용됩니다(SIGINT가 2인 시스템에서는 이것이 가장 많습니다).

하지만이는 bash, ksh93 또는 FreeBSD sh에서는 작동하지 않습니다. SIGINT는 130 종료 상태를 사망으로 처리하지 않습니다.그리고 상위 스크립트는 거기서 끝나지 않습니다.

  1. "130으로 나가는 것은 SIGINT로 죽는 것과 다르다"는 점에서 차이점은 무엇입니까?
  2. 왜 "bash, ksh93 또는 FreeBSD sh에서는 이것이 작동하지 않습니다. SIGINT는 130 종료 상태를 사망으로 처리하지 않습니다"?

Bash 매뉴얼에서:

치명적인 신호 번호 N으로 인해 명령이 종료되면 Bash는 128+N 값을 종료 상태로 사용합니다.

SIGINT의 신호 번호는 2이므로 SIGINT에서 종료되는 명령의 종료 상태는 130입니다. 그래서 제 생각에는 130번 출구를 실행하는 것은 SIGINT를 사용한 죽음과 동일하며, 130번 출구 상태는 죽음 신호로 간주됩니다.

감사해요.

답변1

$?마지막 명령이 SIGINT로 종료된 후 표시되는 130(128+SIGINT)은 일부 쉘에 의해 발생합니다(예: bash다른 쉘은 다른 표현을 사용합니다(예: ksh93의 256+signum, yash signum의 128+256+, / in sigint또는 기타 텍스트). 표현).sigquit+corerces프로세스 종료 시 기본 종료 코드는 무엇입니까?더 알아보기.

프로세스는 자식을 기다리고 상태를 쿼리할 수 있습니다.

  • 정지된 경우(어떤 신호를 사용할지)
  • 복원된 경우
  • 죽으면 (어떤 신호로)
  • 만약 있다면갇힌(을 위한d 과정)
  • 넘어지면핵무기
  • 시스템 호출을 통해 정상적으로 종료할지 여부 _exit()(어떤 종료 코드를 사용할지)

이를 위해 , , , (더 이상 사용되지 않는 , 참조) 중 하나를 사용하거나 wait()SIGCHLD waitpid()시스템 waitid()호출 wait3()wait4()핸들러를 사용합니다.

이러한 시스템 호출은 위의 모든 정보를 반환합니다. ( waitid()일부 시스템을 제외하고 정상적으로 종료되는 자식 프로세스에 전달된 숫자 중 가장 낮은 8비트만 _exit()사용할 수 있습니다.)

그러나 bash(Bourne 및 csh와 같은 대부분의 쉘은) 모든 정보를 8자리 숫자로 묶습니다 $?( $?정상적으로 종료된 프로세스의 종료 코드 중 가장 낮은 8자리, 종료되거나 중단되거나 트랩된 경우 128+signum입니다. 다른 모든 정보는 사용할 수 없습니다). 분명히 일부 정보가 누락되었습니다. 특히, SIGINT로 인해 $?프로세스가 실행되었는지, 종료되었는지 스스로 알 수 없습니다 ._exit(130)

bash프로세스가 언제 종료되는지 명확하게 알 수 있습니다. 예를 들어 백그라운드 프로세스가 종료되면 다음이 표시됩니다.

[1]+  Interrupt               sleep 20

그러나 에서는 $?SIGINT에 의해 종료되었는지 또는 호출되었는지를 알 수 있는 충분한 정보를 제공하지 않습니다 _exit(130).

대부분의 쉘은 이 변환을 수행하므로 애플리케이션은 _exit(number_greater_than_127)신호를 통해 종료를 보고하는 것 외에는 아무것도 수행하지 않습니다.

그럼에도 불구하고 프로세스가 를 실행하면 _exit(130)이를 기다리는 프로세스는 신호에 의해 종료되는 것이 아니라 프로세스가 정상적으로 종료되었음을 감지합니다. C에서는 WIFEXITED()다음을 반환합니다.진짜, WIFSIGNALED()false를 반환합니다.

bash$?프로세스 자체는 SIGINT로 인해 프로세스가 종료되었다고 생각하지 않습니다(비록 SIGINT에 의해 종료된 것과 동일한 값을 가질 수 있다고 생각하게 하더라도 ).

따라서 이는 SIGINT 의 특수 처리를 트리거하지 않습니다 bash. 스크립트 내에서 bash현재 스크립트에서 실행 중인 명령은 모두 SIGINT를 수신합니다 ^C(모두 동일한 프로세스 그룹에 있기 때문입니다).

bash대기 중인 명령도 SIGINT에서 종료되는 경우에만 SIGINT 수신 시 종료됩니다(예를 들어 스크립트에서 vi 이하를 실행하고 ^C를 사용하여 일부 콘텐츠를 유발하거나 종료 vi하지 않는 작업을 중단한다는 아이디어입니다. 종료 / 나중에 돌아올 less때 스크립트는 사라지지 않습니다 ).viless

명령이 SIGINT 핸들러에서 실행을 bash기다리고 있는 경우 해당 SIGINT에서 종료되지 않습니다(자식 프로세스가 중단되었다고 믿지 않기 때문에 중단되었다고 생각하지 않습니다)._exit(130)bash

그렇기 때문에 신고하고 싶을 때SIGINT로 인해 사망, 저것핸들러에서 해당 신호를 받은 후 실제로 추가 처리를 수행하더라도 실제로는 중단됩니다., 을 수행해서는 안 되지만 _exit(130)SIGINT로 실제로 자살해야 합니다(SIGINT에 대한 기본 핸들러를 복원한 후). 셸에서는 다음과 같습니다.

trap '
  extra processing
  trap - INT # restore SIGINT handler
  kill -s INT "$$" # report to the parent that we have indeed been
                   # interrupted
  ' INT

관련 정보