Ctrl-C가 kill -2와 다르게 동작하는 이유

Ctrl-C가 kill -2와 다르게 동작하는 이유

SIGINT를 처리하고 정상적으로 종료하도록 되어 있는 프로그램이 있습니다. 이 프로그램을 백그라운드에서 실행하지 않고 터미널에서 실행할 때 Ctrl-C를 사용하여 프로그램을 닫을 수 있습니다. 로그를 확인하면 모든 것이 예상대로 작동하고 있음을 알 수 있습니다.

별도의 터미널을 열고 호출하면 kill -2 [pid]아무 kill -s INT [pid]작업도 수행되지 않습니다. 로그에는 아무 것도 표시되지 않으며 프로그램을 시작한 터미널에서 Ctrl-C를 누를 때까지 프로그램은 평소처럼 계속 실행됩니다.

Ctrl-C가 신호를 보내는 방식과 Kill이 신호를 보내는 방식 사이에 차이점이 있습니까?

추가 세부 사항:

CLASSPATH이 프로그램은 일부 환경 변수(예: )를 설정한 다음 java [main class]Ctrl-Z를 누르고 ps다음과 같이 결과를 실행하는 bash 쉘 스크립트에 의해 시작되는 Java 애플리케이션입니다 .

$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
mdeck    10251 10250  0 11:48 pts/2    00:00:00 -bash
mdeck    13405 10251  0 18:12 pts/2    00:00:00 /bin/bash /usr/local/bin/myapp.sh
mdeck    13509 13405 25 18:12 pts/2    00:00:03 java com.company.MyApp
mdeck    13526 10251  0 18:13 pts/2    00:00:00 ps -f

Gilles가 요청한 stty 출력은 다음과 같습니다.

$ stty -a </dev/pts/2
speed 38400 baud; rows 40; columns 203; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

답변1

한 가지 가능성은 프로그램이 Ctrl+ C시퀀스를 캡처한다는 것입니다. stty -a의 출력을 확인합니다 . 이 intr설정은 SIGINT 신호를 보내는 키 조합(있는 경우)을 나타내고 isig신호 키가 활성화되었는지( -isig비활성화됨을 의미)를 나타냅니다.

프로그램이 여러 프로세스로 구성된 경우 Ctrl+를 눌러 C프로세스의 모든 프로세스에 SIGINT를 보냅니다.프로세스 그룹. 프로세스 중 하나가 아닌 프로세스 그룹에 신호를 보내도 동일한 효과를 얻을 수 있습니다. 프로세스 그룹에 신호를 보내려면 먼저 해당 리더를 결정합니다. 이는 다른 모든 프로세스를 시작하는 첫 번째 프로세스입니다. 프로세스 그룹을 백그라운드에서 실행하는 경우 PID가 표시합니다 jobs -l. 프로세스 그룹 리더의 PID는 PGID(프로세스 그룹 ID)입니다. 신호를 음극 터미널로 보냅니다. 예를 들어 PGID가 1234인 경우 kill -INT -1234.

프로그램이 래퍼 스크립트와 기본 애플리케이션으로 구성된 경우 고려해야 할 두 가지 시나리오가 있습니다. 기본 애플리케이션이 종료된 후 래퍼 스크립트가 즉시 종료되도록 정리가 필요하지 않은 경우 래퍼 스크립트 호출을 수행합니다 exec.

#!/bin/sh
export SOMEVAR=somevalue
exec /path/to/application "$@"

이런 방식으로 애플리케이션은 스크립트를 대체하고 해당 PID를 상속받을 수 있습니다. 일부 쉘은 다른 프로그램으로 끝나는 스크립트를 실행하도록 최적화하지만 전부는 아닙니다. 이 방법은 스크립트가 일부 정리(예: 임시 파일 삭제)를 수행해야 하는 경우에는 작동하지 않습니다.

스크립트가 신호를 감지하고 이를 애플리케이션에 전송하도록 하는 것을 고려하십시오. 전체 프로세스의 개요는 다음과 같습니다.

/path/to/application "$@" &
app_pid=$!
trap -INT 'kill -INT $app_pid'
wait $!
rm /temp/file

답변2

원래 질문의 댓글에서 @Gilles가 묻는 질문을 바탕으로 kill -2내가 보내는 명령이 신호 자체를 처리하는 프로세스가 아니라 응용 프로그램을 시작한 래퍼 스크립트의 pid에 대한 것이라는 것을 깨달았습니다.

내 질문의 pid를 사용하면 kill -s 13405응용 프로그램에 올바르게 신호를 보내지 않지만 호출은 kill -s 13509예상대로 작동합니다.

이제 제 질문은 SIGINT를 하위 프로세스에 전파하기 위해 래퍼 스크립트를 업데이트하는 방법입니다. 이에 대해서는 별도의 질문을 작성하겠습니다.

관련 정보