Linux로 부팅하고 작은 Bash 스크립트를 실행하는 라이브 CD가 있습니다. 이 스크립트는 두 번째 프로그램 (일반적으로 컴파일 된 C ++ 바이너리)을 검색하고 실행합니다.
Ctrl+ 를 눌러 두 번째 프로그램을 중단 할 수 있습니다 C. 무엇을 해야 일어날 것은 그 두 번째 프로그램은 정지하고, 배쉬 스크립트는 정리를 실행하고 있습니다. 무엇 실제로 일어나는 것은 기본 응용 프로그램 및 배쉬 스크립트가 모두 종료 할 것입니다. 어떤 문제입니다.
그래서 trap
내장을 사용하여 Bash에게 SIGINT를 무시하도록 지시했습니다. 이제 Ctrl+ C는 C ++ 응용 프로그램을 종료하지만 Bash는 계속 실행됩니다. 큰.
오 예. 때때로 “두 번째 응용 프로그램”은 또 다른 Bash 스크립트입니다. 그리고에 그 경우, Ctrl+ C지금 않습니다 아무것도 무엇이든지를 .
분명히이 물건의 작동 방식에 대한 나의 이해가 잘못되었습니다 … 사용자가 Ctrl+를 누를 때 어떤 프로세스가 SIGINT를 얻는 지 어떻게 제어 C합니까? 이 신호를 하나의 특정 프로세스로 보내려고 합니다 .
답변
인터넷의 얼굴을 검색하는 많은 시간 후에, 나는 그 답을 찾았습니다.
-
TTY 드라이버에는 Foreground Process Group이라는 개념이 있습니다.
-
Ctrl+ 를 누르면 CTTY 가 Foreground Process Group의 모든 프로세스 로 전송
SIGINT
합니다 . ( 이 블로그 항목 도 참조하십시오 .)
그렇기 때문에 컴파일 된 바이너리 와 이를 시작하는 스크립트가 모두 혼란스러워집니다. 사실 나는 주 응용 프로그램이 시작 스크립트가 아닌 이 신호를 수신하기를 원합니다 .
해결책은 분명합니다. 응용 프로그램을 새로운 프로세스 그룹에 배치하고이 TTY를위한 Foreground Process Group으로 만들어야합니다. 분명히 그렇게하는 명령은
setsid -c <applcation>
그리고 그게 다야. 이제 사용자가 Ctrl+를 누르면 CSIGINT가 응용 프로그램 (및 자식이있을 수있는 자식)으로 보내지고 다른 사람은 보내지 않습니다. 내가 원하는 것입니다.
-
setsid
그 자체로 애플리케이션을 새로운 프로세스 그룹 (실제로 프로세스 그룹의 그룹 인 완전히 새로운 “세션”)에 넣습니다. -
-c
플래그를 추가 하면이 새 프로세스 그룹이 현재 TTY의 “전경”프로세스 그룹이됩니다. (즉, +SIGINT
를 누르면 나타납니다 )CtrlC
Bash가 새로운 프로세스 그룹에서 프로세스를 실행하거나 실행하지 않을 때에 대해 많은 상충되는 정보를 보았습니다. (특히 “대화식”과 “비 대화식”셸에서는 다른 것으로 보입니다.) 나는 이것이 당신이 영리한 파이프 속임수 로 작동하게 할 수 있다는 제안을 보았습니다 … 모릅니다. 그러나 위의 접근 방식은 저에게 효과적입니다.
답변
f01에 대한 의견에서 언급했듯이 SIGTERM을 자식 프로세스로 보내야합니다. ^ C를 포착하고 자식 프로세스에 신호를 보내는 방법을 보여주는 두 개의 스크립트가 있습니다.
먼저 부모님.
트랩 테스트
#!/bin/bash
# trap test
# Written by PM 2Ring 2014.10.23
myname=$(basename "$0")
child=sleeploop
set_trap()
{
sig=$1
msg="echo -e \"\n$myname received ^C, sending $sig to $child, $pid\""
trap "$msg; kill -s $sig $pid" SIGINT
}
trap "echo \"bye from $myname\"" EXIT
echo "running $child..."
./$child 5 &
pid=$!
# set_trap SIGINT
set_trap SIGTERM
echo "$child pid = $pid"
wait $pid
echo "$myname finished waiting"
그리고 지금, 아이.
슬립 루프
#!/bin/bash
# child script for traptest
# Written by PM 2Ring 2014.10.23
myname=$(basename "$0")
delay="$1"
set_trap()
{
sig=$1
trap "echo -e '\n$myname received $sig signal';exit 0" $sig
}
trap "echo \"bye from $myname\"" EXIT
set_trap SIGTERM
set_trap SIGINT
#Select sleep mode
if false
then
echo "Using foreground sleep"
Sleep()
{
sleep $delay
}
else
echo "Using background sleep"
Sleep()
{
sleep "$delay" &
wait $!
}
fi
#Time to snooze :)
for ((i=0; i<5; i++));
do
echo "$i: sleeping for $delay"
Sleep
done
echo "$myname terminated normally"
traptest가 SIGTERM을 보내면 잘 동작하지만 traptest가 SIGINT를 보내면 sleeploop는 그것을 보지 않습니다.
슬립 루프가 SIGTERM을 포착하고 슬립 모드가 포 그라운드이면 현재 슬립에서 깨어날 때까지 신호에 응답 할 수 없습니다. 그러나 수면 모드가 백그라운드이면 즉시 응답합니다.
답변
시작 bash 스크립트에서.
-
두 번째 프로그램의 PID를 추적
-
SIGINT를 잡아
-
SIGINT를 잡으면 두 번째 프로그램 PID에 SIGINT를 보냅니다.