我有一个启动几个后台子进程的 shell 脚本。我希望它们始终运行 - 除非父进程退出或被杀死(所以我让子进程处于一个循环中,如果退出则总是重新启动)。
如果我直接执行这个脚本,似乎效果相对较好。但一旦我sudo
这样做,它就无法正确清理其他进程:
#!/bin/bash
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
# Start first background thing
while true;
do
sleep 1
echo "SOME PROCESS RUNNING IN THE BACKGROUND"
echo "SHOULD AUTO-RESTART IF IT GETS KILLED OR CRASHES"
sleep 5
done &
# Start second background thing
while true;
do
sleep 3
echo "ANOTHER ONE..."
sleep 3
done &
# Wait for quit keypress
while true
do
echo "Press 'Q' to quit"
read -rsn1
if [ $REPLY == "q" ] || [ $REPLY == "Q" ]; then
echo "Are you sure? [Y/N]"
read -rsn1
if [ $REPLY == "y" ] || [ $REPLY == "Y" ]; then
kill -- -$$
exit
fi
fi
echo ""
sleep 1
done
# Wait
wait
当我执行 sudo 时,如果我按 CTRL+C 或按“Q”退出,它将退出父(主)进程,但不会退出子进程,并且我收到此错误:
adam@TG-BBCAM-01:~ $ sudo ./temp.sh
Press 'Q' to quit
Are you sure? [Y/N]
./temp.sh: line 31: kill: (-29098) - No such process
./temp.sh: line 1: kill: (-29098) - No such process
adam@TG-BBCAM-01:~ $ SOME PROCESS RUNNING IN THE BACKGROUND
SHOULD AUTO-RESTART IF IT GETS KILLED OR CRASHES
ANOTHER ONE...
SOME PROCESS RUNNING IN THE BACKGROUND
SHOULD AUTO-RESTART IF IT GETS KILLED OR CRASHES
ANOTHER ONE...
SOME PROCESS RUNNING IN THE BACKGROUND
SHOULD AUTO-RESTART IF IT GETS KILLED OR CRASHES
ANOTHER ONE...
SOME PROCESS RUNNING IN THE BACKGROUND
显然,因为它没有杀死孩子们,所以他们仍然在运行,并仍然在我的 shell 中输出。当我不使用 sudo 时,效果很好。
它似乎是kill -- -$$
我脚本的陷阱和“按键监视器”部分。注释掉其中一个并不能解决另一个问题。
有谁知道我该如何解决这个问题?我只是希望它能在大多数情况下工作(至少,无论是否需要 sudo)。
谢谢!
答案1
是的kill -- -"$pgid"
,那就是它必须是一个过程团体ID。仅当 shell 是进程组领导者时才有效,但从交互式 shellkill -- -"$$"
运行时则不然:sudo
$ sudo bash -c 'ps -j; exit'
PID PGID SID TTY TIME CMD
26786 26786 29719 pts/39 00:00:00 sudo
26794 26786 29719 pts/39 00:00:00 bash
26795 26786 29719 pts/39 00:00:00 ps
sudo
是流程组领导者,而不是bash
。
所以,你需要做kill -- -"$(ps -o pgid= -p "$$")"
或者简单地:
kill 0
这是杀死你自己的进程组的命令。
无论如何,只有从交互式 shell(执行作业控制)单独调用脚本时,这才是有效的做法。
另请注意,在:
(the-script; echo "$?")
或者:
the-script | cmd
第一种情况或cmd
第二种情况中的子 shell 也放置在同一进程组中,因此也会被杀死kill 0
。