bash Ctrl-C를 수신할 때 전경 프로세스(스크립트)에 의해 시작된 백그라운드 하위 프로세스를 식별하는 방법

bash Ctrl-C를 수신할 때 전경 프로세스(스크립트)에 의해 시작된 백그라운드 하위 프로세스를 식별하는 방법

제 질문은 WCE(Waiting and Cooperative Exit)와는 아무런 관련이 없습니다. 대화형 셸(bash)에서 포그라운드 작업으로 스크립트를 시작한다고 가정해 보겠습니다.

#! /bin/bash
# script name: foreback.sh
sleep 100m &   # child process in bg
sleep 200m &   # ditto
sleep 300m &   # ditto
sleep 7000m    # child process in fg

exit 0

이 스크립트가 실행되는 동안 Ctrl-C를 누르면 모든 포그라운드 프로세스(내 스크립트의 프로세스 - 상위 프로세스 - 예상되는 네 번째 잠자는 하위 프로세스)가 종료됩니다.

내 질문은: 포그라운드 프로세스 그룹이 SIGINT를 수신할 때 이러한 백그라운드 하위 프로세스를 어떻게 식별합니까?

신호를 보내기 전에 다음 ps 출력을 확인하십시오.

TT         TPGID    PPID     PID    PGID    SESS STAT COMMAND
pts/0       9373    9259    9282    9282    9282 Ss    |       \_ /bin/bash
pts/0       9373    9282    9373    9373    9282 S+    |       |   \_ /bin/bash ./foreback.sh
pts/0       9373    9373    9374    9373    9282 S+    |       |       \_ sleep 100m
pts/0       9373    9373    9375    9373    9282 S+    |       |       \_ sleep 200m
pts/0       9373    9373    9376    9373    9282 S+    |       |       \_ sleep 300m
pts/0       9373    9373    9377    9373    9282 S+    |       |       \_ sleep 7000m

상위 및 하위 프로세스는 둘 다 상위 전경 프로세스의 PID인 동일한 터미널 프로세스 그룹(TPGID)에 속하고 STAT 열에 더하기 기호가 표시되므로 일종의 "전경 콤플렉스"로 나타납니다. SIGINT를 Ctrl-C를 통해 포그라운드 프로세스 그룹으로 보내거나 kill -INT를 통해 프로세스 그룹(PGID)으로 보내는 경우 -- -PGID, 쉘은 종료할 프로세스와 활성 상태를 유지할 프로세스를 어떻게 알 수 있습니까? 위에서 언급한 Ctrl-C 또는 프로세스 그룹을 사용하여 종료한 후 ps 출력은 다음과 같습니다.

TT         TPGID    PPID     PID    PGID    SESS STAT COMMAND
pts/0       9282    9259    9282    9282    9282 Ss+   |       \_ /bin/bash
pts/0       9282    1742    9374    9373    9282 S     \_ sleep 100m
pts/0       9282    1742    9375    9373    9282 S     \_ sleep 200m
pts/0       9282    1742    9376    9373    9282 S     \_ sleep 300m

상위 프로세스의 백그라운드에서 시작된 세 개의 하위 프로세스는 여전히 활성 상태이며 STAT 열은 더하기 기호가 누락되어 백그라운드에 있음을 나타내며 터미널 프로세스 그룹은 이제 대화형 셸의 그룹입니다. 이것이 바로 그 방법입니다.

그러나 SIGINT가 포그라운드 프로세스 그룹으로 전송되면 "나를 죽이지 마십시오. 나는 백그라운드 프로세스입니다"라는 "플래그"가 표시되지 않습니다.

나는 다음과 같은 일이 일어나고 있다고 생각합니다.

  1. SIGINT는 포그라운드 프로세스 그룹으로 전송됩니다.

  2. 신호를 수신하고 이에 반응하는 첫 번째 프로세스는 PID가 TPGID(전경 프로세스 그룹 리더)와 동일한 프로세스입니다.

  3. 프로세스가 종료되면 쉘은 어떤 하위 프로세스가 백그라운드 프로세스로 시작되었는지 "기억"하고 해당 TPGID를 원래 TPGID에서 대화형 쉘의 TPGID로 변경하여 더 이상 이전 포그라운드 프로세스 그룹에 속하지 않게 합니다. 시작되지 않고 TPGID 변경을 경험하지 않은 나머지 하위 항목은 SIGINT를 수신하고 반응합니다(또는 다른 처리가 발생하지 않으면 종료).

몇 주 동안 수많은 웹사이트를 탐색했지만 정답을 찾을 수 없었습니다.

어떤 아이디어가 있나요? ? ? ? 감사해요

답변1

기본적으로 비대화형 셸에는 작업 제어 기능이 없으므로 스크립트가 실행하는 모든 프로세스는 셸을 실행하는 프로세스와 동일한 프로세스 그룹에 있습니다. 이 프로세스 그룹은 스크립트가 시작되었는지/포그라운드에 배치되었는지 여부에 따라 대화형 쉘 시작 스크립트의 터미널 포그라운드 프로세스 그룹이 됩니다.

그러나 작업 제어가 비활성화되면 POSIX 쉘은이 요구 사항:

2.11. 신호 및 오류 처리

쉘이 비동기 목록을 실행할 때 작업 제어가 비활성화된 경우(set -m 설명 참조) 목록의 명령은 쉘의 SIGINT 및 SIGQUIT 신호에 대한 무시(SIG_IGN) 신호 작업을 상속합니다. 다른 모든 경우에, 쉘에 의해 실행되는 명령은 트랩 특수 내장 함수에 의해 신호 작동이 수정되지 않는 한 부모로부터 쉘에 의해 상속된 것과 동일한 신호 작동을 상속해야 합니다(트랩 참조).

따라서 이는 비동기 목록이 Ctrl+ cCtrl+ 의 영향을 받지 않는 대략적인 형태의 "작업" 제어입니다 \.

리눅스의 경우:

$ sh -c 'sleep 10 & grep SigIgn "/proc/$!/status"'
SigIgn: 0000000000000006
$ kill -l INT QUIT
2
3

( SigIgn위는 비트마스크입니다. 이 경우 SIGINT 및 SIGQUIT에 해당하는 두 번째 세 번째 비트가 설정됩니다.)

이러한 키 조합을 눌렀을 때 터미널이 이러한 문자를 보내면 ^C^\은 이러한 신호 전달에 참여하지 않습니다. 커널(tty 드라이버)은 터미널의 포그라운드 프로세스 그룹에 있는 프로세스에 신호를 보냅니다.

/dev/pts/0TPGID는 실제 프로세스가 아닌 터미널 장치(귀하의 경우)의 속성입니다 . ps 터미널에 연결된 세션에서 실행 중인 모든 프로세스에 대해 항상 동일한 값이 표시됩니다. 작업(프로세스 그룹)이 전경으로 가져오면 대화형 쉘은 다음을 수행하여 tcsetpgrp(terminal_fd, its_pid)터미널 드라이버에게 다음을 알립니다. 이는 이 터미널의 전경 프로세스 그룹이고 다른 모든 것은 배경에 있습니다.

실제로 살아남은 sleep프로세스는 스크립트가 종료되기 때문에 백그라운드에서 실행되고 ^C있으므로 이를 기다리고 있는 대화형 셸은 터미널의 포그라운드 프로세스 그룹을 다시 자체 프로세스 그룹으로 변경합니다.

관련 정보