백그라운드 프로세스를 실행하도록 쉘 스크립트를 설정하려고하는데 쉘 스크립트 Ctrlc가 자식을 죽인 다음 종료됩니다.
내가 생각해 낸 최선은 이것입니다. 이 나타납니다 kill 0 -INT
또한 대기가 발생하기 전에 스크립트를 죽이고, 그래서 아이들 전에 쉘 스크립트 다이 완료.
이 쉘 스크립트를 보내서 아이들이 죽을 때까지 기다리는 방법에 대한 아이디어가 INT
있습니까?
#!/bin/bash
trap 'killall' INT
killall() {
echo "**** Shutting down... ****"
kill 0 -INT
wait # Why doesn't this wait??
echo DONE
}
process1 &
process2 &
process3 &
cat # wait forever
답변
당신의 kill
명령은 거꾸로 있습니다.
많은 UNIX 명령과 마찬가지로 마이너스로 시작하는 옵션이 다른 인수보다 먼저 나와야합니다.
당신이 쓰는 경우
kill -INT 0
-INT
옵션으로 보고 전송 SIGINT
합니다 0
( 0
현재 프로세스 그룹의 모든 프로세스를 의미하는 특수 번호).
하지만 글을 쓰면
kill 0 -INT
이 표시되고 0
더 이상 옵션이 없다고 결정하므로 SIGTERM
기본적으로 사용 됩니다. 그리고 보내는 것을 당신이 한 것과 같은, 현재 프로세스 그룹에
kill -TERM 0 -INT
(또한 전송 시도 할 것이다 SIGTERM
에 -INT
구문 오류가 발생할 것이다, 그러나 그것은 전송 SIGTERM
에 0
첫번째, 멀리 것을 얻을 수 없다.)
따라서 주 스크립트는 and SIGTERM
를 실행하기 전에를 받고 있습니다.wait
echo DONE
더하다
trap 'echo got SIGTERM' TERM
바로 상단에
trap 'killall' INT
이것을 증명하기 위해 다시 실행하십시오.
Stephane Chazelas가 지적한 바와 같이, 배경이있는 자녀 ( process1
등)는 SIGINT
기본적으로 무시 합니다.
어쨌든 보내는 SIGTERM
것이 더 의미가 있다고 생각 합니다.
마지막으로, 나는 kill -process group
아이들에게 먼저 갈 것이 확실하지 않다 . 종료하는 동안 신호를 무시하는 것이 좋습니다.
따라서 이것을 시도하십시오 :
#!/bin/bash
trap 'killall' INT
killall() {
trap '' INT TERM # ignore INT and TERM while shutting down
echo "**** Shutting down... ****" # added double quotes
kill -TERM 0 # fixed order, send TERM not INT
wait
echo DONE
}
./process1 &
./process2 &
./process3 &
cat # wait forever
답변
불행히도 백그라운드에서 시작된 명령은 SIGINT를 무시하도록 쉘에 의해 설정되며 더 나쁜 것은 무시할 수 없습니다 trap
. 그렇지 않으면, 당신이 할 일은
(trap - INT; exec process1) &
(trap - INT; exec process2) &
trap '' INT
wait
process1과 process2는 터미널의 포 그라운드 프로세스 그룹과 동일한 프로세스 그룹의 일부이므로 Ctrl-C를 누르면 SIGINT를 얻습니다.
위의 코드는 pdksh 및 zsh와 작동하며 POSIX 호환이 아닙니다.
다른 쉘에서는 다음과 같이 SIGINT의 기본 핸들러를 복원하기 위해 다른 것을 사용해야합니다.
perl -e '$SIG{INT}=DEFAULT; exec "process1"' &
SIGTERM과 같은 다른 신호를 사용하십시오.
답변
프로세스를 죽이고 프로세스가 끝날 때까지 기다리 길 원하는 사람들에게는 :
신호 유형 당 최대 60 초 동안 대기합니다.
경고 :이 답변은 킬 신호를 포착하여 발송하는 것과 관련이 없습니다.
# close_app_sub GREP_STATEMENT SIGNAL DURATION_SEC
# GREP_STATEMENT must not match itself!
close_app_sub() {
APP_PID=$(ps -x | grep "$1" | grep -oP '^\s*\K[0-9]+' --color=never)
if [ ! -z "$APP_PID" ]; then
echo "App is open. Trying to close app (SIGNAL $2). Max $3sec."
kill $2 "$APP_PID"
WAIT_LOOP=0
while ps -p "$APP_PID" > /dev/null 2>&1; do
sleep 1
WAIT_LOOP=$((WAIT_LOOP+1))
if [ "$WAIT_LOOP" = "$3" ]; then
break
fi
done
fi
APP_PID=$(ps -x | grep "$1" | grep -oP '^\s*\K[0-9]+' --color=never)
if [ -z "$APP_PID" ]; then return 0; else return "$APP_PID"; fi
}
close_app() {
close_app_sub "$1" "-HUP" "60"
close_app_sub "$1" "-TERM" "60"
close_app_sub "$1" "-SIGINT" "60"
close_app_sub "$1" "-KILL" "60"
return $?
}
close_app "[f]irefox"
이름이나 인수로 죽일 앱을 선택합니다. grep 자체와 일치하지 않도록 앱 이름의 첫 글자를 괄호로 묶습니다.
약간의 변경으로, 명령문 pidof process_name
대신 PID 또는 더 간단한 것을 직접 사용할 수 있습니다 ps
.
코드 정보 : 마지막 grep은 후행 공백없이 PID를 얻는 것입니다.
답변
원하는 배경 프로세스를 관리하는 것이 bash 작업 제어 기능을 사용하지 않는 이유는 무엇입니까?
$ gedit &
[1] 2581
$ emacs &
[2] 2594
$ jobs
[1]- Running gedit &
[2]+ Running emacs &
$ jobs -p
2581
2594
$ kill -2 `jobs -p`
$ jobs
[1]- Interrupt gedit
[2]+ Done emacs
답변
그래서 나는 이것으로도 고민했다. Bash에서는 함수를 정의하고 멋진 기능을 수행 할 수 있습니다. 내 동료와 나는을 사용 terminator
하므로 배치 실행의 경우 출력을보고 싶다면 일반적으로 터미네이터 창을 모두 생성합니다 ( tmux
탭 보다 우아하지 않지만 GUI와 유사한 인터페이스 haha를 사용할 수 있음).
여기에 내가 만든 설정과 실행할 수있는 물건의 예가 있습니다.
#!/bin/bash
custom()
{
terun 'something cool' 'yes'
run 'xclock'
terun 'echoes' 'echo Hello; echo Goodbye; read'
func()
{
local i=0
while :
do
echo "Iter $i"
let i+=1
sleep 0.25
done
}
export -f func
terun 'custom func' 'func'
}
# [ Setup ]
run()
{
"$@" &
# Give process some time to start up so windows are sequential
sleep 0.05
}
terun()
{
run terminator -T "$1" -e "$2"
}
finish()
{
procs="$(jobs -p)"
echo "Kill: $procs"
# Ignore process that are already dead
kill $procs 2> /dev/null
}
trap 'finish' 2
custom
echo 'Press <Ctrl+C> to kill...'
wait
그것을 실행
$ ./program_spawner.sh
Press <Ctrl+C> to kill...
^CKill: 9835
9840
9844
9850
$
@Maxim을 편집 하고 방금 제안을 보았으므로 훨씬 간단합니다! 감사!