我有一个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)的任何相当新的版本。
参考文献:
自从你问我的问题以来,我必须将其标记为答案,这很有帮助。但是,我说“这个过程实际上可以是一个交互式子shell(例如bash -i)”,我应该添加“我不想将代表性进程置于后台,因为它可能是一个交互式shell”。 – bgoodr
请记住,交互式子shell的用户无论如何都可以设置自己的陷阱,以避免被调用者中断shell。 – chepner
@bgoodr你有没有找到一个解决方案,不需要把过程放在后台? – trex005