2015-10-20 44 views
6

我有一个Bash脚本,它在前台运行一个长时间运行的进程。当它收到一个SIGQUIT信号时,它应该执行各种清理操作,比如杀死它自己及其所有子进程(通过杀死进程组等)。一个最小的脚本,应该抓住信号,如下图所示(称为test_trap.sh):如何使用Bash运行前景子进程可靠地使用陷阱

#!/bin/bash 

trap 'echo "TRAP CAUGHT"; exit 1' QUIT # other required signals are omitted for brevity 

echo starting sleep 
sleep 11666 
echo ending sleep 

echo done 

我想给SIGHUP信号发送到test_trap.sh脚本的过程。但是,发送SIGHUP到test_trap.sh不会触发陷阱表达式,但只有当我向孩子发送信号时sleep 11666过程才会触发陷阱。下面是一个示范会议:

bash-4.1$ test_trap.sh & 
[1] 19633 
bash-4.1$ starting sleep 

bash-4.1$ kill -s SIGQUIT 19633 
bash-4.1$ jobs 
[1]+ Running     test_trap.sh & 
bash-4.1$ ps -ef --forest --cols=10000 | grep '11666\|test_trap.sh' | grep -v grep 
theuser 19633 12227 0 07:40 pts/4 00:00:00    \_ /bin/bash ./test_trap.sh 
theuser 19634 19633 0 07:40 pts/4 00:00:00    | \_ sleep 11666 
bash-4.1$ kill -s SIGQUIT 19634 
bash-4.1$ Quit (core dumped) 
TRAP CAUGHT 

[1]+ Exit 1     test_trap.sh 
bash-4.1$ ps -ef --forest --cols=10000 | grep '11666\|test_trap.sh' | grep -v grep 
bash-4.1$ 

请注意,“睡眠11666”只是一个代表性的过程。该过程实际上可以是交互式子外壳(例如,bash -i)。

为什么父母test_trap.sh进程没有捕捉到SIGHUP信号?为什么只有在sleep 11666的过程发出信号时才会触发陷阱?

我不想使用不可捕获的SIGKILL,因为我需要在陷阱表达式中进行各种清理操作。

此脚本适用于包含Bash的任何Linux发行版(例如,不是Cygwin)的任何相当新的版本。

参考文献:

  1. killing Parent process along with child process using SIGKILL
  2. Kill bash and child process

回答

6

bash必须等待sleep才能执行处理程序。一个很好的解决方法是在后台运行sleep,然后立即等待它。虽然sleep是不可中断的,但wait不是。

trap 'kill $sleep_pid; echo "TRAP CAUGHT"; exit 1' QUIT 

echo starting sleep 
sleep 11666 & 
sleep_pid=$! 
wait 
echo ending sleep 

echo done 

sleep_pid记录,并用它来杀死从处理程序sleep是可选的。

+1

自从你问我的问题以来,我必须将其标记为答案,这很有帮助。但是,我说“这个过程实际上可以是一个交互式子shell(例如bash -i)”,我应该添加“我不想将代表性进程置于后台,因为它可能是一个交互式shell”。 – bgoodr

+0

请记住,交互式子shell的用户无论如何都可以设置自己的陷阱,以避免被调用者中断shell。 – chepner

+0

@bgoodr你有没有找到一个解决方案,不需要把过程放在后台? – trex005

1

实际上,bash的正在接收的信号,但它是在等待sleep命令结束的不间断状态。当它结束时,bash会对信号做出反应并执行陷阱。

while true 
do 
    sleep 1 
done 

有了,如果你将信号发送到bash的过程中,会尽快作出反应,当前执行的sleep命令:

你可以用短sleep命令的循环替换长sleep命令结束,即发送后最多1秒。

+0

谢谢,但看到我的回应在http://stackoverflow.com/questions/33240221/how-to-use-trap-reliably-using-bash-running-foreground-child-processes#comment54286155_33241062给予@ chepner的答案。如果我只想睡觉,那么你的答案就足够了,但这只是一个代表性的过程,我希望允许它在前台运行,因为它最终可能是一个交互式的“bash -i”过程。 – bgoodr

0

尝试使用信号SIGINT(与按Ctrl + C发送的信息相同)而不是SIGKILL。其他信号仅在bash可以处理I/O或其他条件时有效。