INT에 대한 트래핑이 서브셸에서 작동하지 않습니다.

INT에 대한 트래핑이 서브셸에서 작동하지 않습니다.
$ bash -c "trap \"echo INT\" INT; sleep 3" & pid=$!; sleep 1; kill -INT $pid; wait
[1] 27811
INT
[1]+  Done                    bash -c "trap \"echo INT\" INT; sleep 3"

$ (bash -c "trap \"echo INT\" INT; sleep 3" & pid=$!; sleep 1; kill -INT $pid; wait)

SIGINT두 번째 경우에 핸들러가 호출되지 않는 이유를 설명할 수 있습니까 ?

답변1

작업 제어는 사용자가 단일 로그인 세션 내에서 여러 프로세스 그룹(또는 작업) 간에 이동할 수 있도록 하는 프로토콜을 나타냅니다.

https://www.gnu.org/software/libc/manual/html_node/Job-Control.html

일반적으로 대화형 셸에서는 활성화되고 비대화형 셸에서는 비활성화됩니다.

$ echo $-; sleep 1 & fg
himBHs
[1] 84366
sleep 1

$ bash -c 'echo $-; sleep 1 & fg'
hBc
bash: line 1: fg: no job control

이 경우... 분명히 작업 제어가 비활성화되어 $-신뢰할 수 없습니다.

$ (echo $-; sleep 1 & fg)
himBHs
bash: fg: no job control

셸은 작업을 각 파이프라인과 연결합니다.

https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html

즉, 작업 제어가 활성화되면 각 파이프라인은 별도의 프로세스 그룹에서 실행됩니다.

pgid.sh:

#!/usr/bin/env bash
ps -o pgid= $$
$ ./pgid.sh >&2 | ./pgid.sh >&2; ./pgid.sh; ./pgid.sh & wait
  93439
  93439
  93443
[1] 93445
  93445
[1]+  Done                    ./a.sh

$ (./pgid.sh >&2 | ./pgid.sh >&2; ./pgid.sh; ./pgid.sh & wait)
  93749
  93749
  93749
  93749

작업 중 하나는 포그라운드 작업이고 나머지는 백그라운드 작업입니다.

백그라운드 작업이 있습니다해서는 안 된다그들을 시작한 껍질에 묶여 있습니다. 쉘을 종료하면 계속 실행됩니다. 따라서 SIGINT기본적으로 중단되어서는 안 됩니다. 작업 제어가 활성화되면 백그라운드 작업이 별도의 프로세스 그룹에서 실행되기 때문에 이 작업이 자동으로 수행됩니다. 작업 제어가 비활성화되면 bash비동기 명령이 무시되고 SIGINT해당 명령(스크립트인 경우 bash)이 이를 재정의하는 것을 허용하지 않습니다.

즉, 여기서는 다음과 같습니다.

$ bash -c "trap 'echo INT' INT; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait

백그라운드 작업( bash -c "trap 'echo INT' INT; sleep 3")은 작업 제어가 활성화된 대화형 셸에 의해 실행됩니다. 결과 백그라운드 작업이 수신되었습니다 SIGINT.

이것을 작업 제어 없이 비대화형 셸로 래핑하면 다음과 같습니다.

$ (bash -c "trap 'echo INT' INT; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait)

bash -c "trap 'echo INT' INT; sleep 3"무시 SIGINT되고 trap ... INT또한 무시됩니다.

이는 다음을 통해 확인할 수 있습니다.

$ bash -c "trap 'echo INT' INT; trap; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait
[1] 293631
trap -- 'echo INT' SIGINT
trap -- '' SIGFPE
INT
[1]+  Done                    bash -c "trap 'echo INT' INT; trap; sleep 3"

$ (bash -c "trap 'echo INT' INT; trap; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait)
trap -- '' SIGINT
trap -- '' SIGQUIT
trap -- '' SIGFPE

$ bash -c 'ps -o pid,ignored,comm,args -p $$' & wait
[1] 345833
    PID          IGNORED COMMAND         COMMAND
 345833 0000000000000000 ps              ps -o pid,ignored,comm,args -p 345833
[1]+  Done                    bash -c 'ps -o pid,ignored,comm,args -p $$'

$ (bash -c 'ps -o pid,ignored,comm,args -p $$' & wait)
    PID          IGNORED COMMAND         COMMAND
 345629 0000000000000006 ps              ps -o pid,ignored,comm,args -p 345629

관련 인용문:

Bash가 실행한 비내장 명령은 신호 처리기를 쉘이 상위로부터 상속받은 값으로 설정합니다.작업 제어가 비활성화되면 비동기 명령이 무시 SIGINT되고SIGQUIT이러한 상속된 핸들러 외에도 명령 대체의 결과로 실행되는 명령은 키보드에서 생성된 작업 제어 신호 및 를 무시 합니다 SIGTTIN.SIGTTOUSIGTSTP

https://www.gnu.org/software/bash/manual/html_node/Signals.html

셸에 들어갈 때 무시되는 신호는 포착하거나 재설정할 수 없습니다.

https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-trap

작업 제어는 프로세스 실행을 선택적으로 중지(일시 중지)하고 나중에 실행을 재개(재개)하는 기능을 말합니다. 사용자는 일반적으로 운영 체제 커널의 터미널 드라이버와 Bash가 제공하는 대화형 인터페이스를 통해 이 기능을 사용합니다.

셸은 작업을 각 파이프라인과 연결합니다. 이는 jobs명령을 사용하여 나열 할 수 있는 현재 실행 중인 작업 테이블을 보유합니다 . Bash가 작업을 비동기적으로 시작하면 다음과 같은 줄이 인쇄됩니다.

[1] 25647

이 작업이 작업 번호이고 1이 작업과 연결된 파이프라인의 마지막 프로세스의 프로세스 ID가 임을 나타냅니다 25647. 단일 파이프라인의 모든 프로세스는 동일한 작업의 구성원입니다. Bash는 작업 추상화를 작업 제어의 기초로 사용합니다.

작업 제어 사용자 인터페이스의 구현을 용이하게 하기 위해 운영 체제는 현재 터미널 프로세스 그룹 ID의 개념을 유지합니다. 이 프로세스 그룹의 구성원(현재 터미널의 프로세스 그룹 ID와 동일한 프로세스 그룹 ID를 가진 프로세스)은 키보드에서 생성된 신호를 수신합니다 SIGINT. 이러한 프로세스를 포그라운드에 있다고 합니다.백그라운드 프로세스는 프로세스 그룹 ID가 터미널 프로세스 그룹 ID와 다른 프로세스입니다. 이러한 프로세스는 키보드에서 생성된 신호의 영향을 받지 않습니다.포그라운드 프로세스만 터미널에서 데이터를 읽을 수 있으며, 사용자가 지정한 경우 stty tostop터미널에 쓸 수 있습니다. 터미널에서 읽기( stty tostop또는 유효한 경우 쓰기)를 시도하는 백그라운드 프로세스는 커널의 터미널 드라이버에서 보낸 () 신호를 가지며 SIGTTIN포착되지 않는 한 정지됩니다.SIGTTOU

https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html

관련 정보