这是parent.sh:
#!/bin/bash
trap 'exit' SIGHUP SIGINT SIGQUIT SIGTERM
if ! [ -t 0 ]; then # if running non-interactively
sleep 5 & # allow a little time for child to generate some output
set -bm # to be able to trap SIGCHLD
trap 'kill -SIGINT $$' SIGCHLD # when sleep is done, interrupt self automatically - cannot issue interrupt by keystroke since running non-interactively
fi
sudo ~/child.sh
这是child.sh:
#!/bin/bash
test -f out.txt && rm out.txt
for second in {1..10}; do
echo "$second" >> out.txt
sleep 1
done
如果在这样的终端中运行父脚本......
~/parent.sh
...大约3秒钟后,按击键发出中断。几秒钟后检查out.txt时,它看起来像......
1
2
3
...因此表明父母和孩子结束(击键)中断。通过实时检查ps -ef
并查看脚本进程在中断之前存在并在中断之后消失来证实这一点。
如果cron调用父脚本,那么......
* * * * * ~/parent.sh
... out.txt的内容总是......
1
2
3
4
5
6
7
8
9
10
...因此表明至少孩子没有结束(kill命令)中断。通过实时检查ps -ef
并在中断之前看到脚本进程存在并且在中断之后只有父进程消失来证实这一点,但是子进程一直持续到它运行它的过程为止。
试图解决......
set -bm
的非交互式调用(这需要孩子的PGID与父级的PGID不同 - 相关提前)。除此之外,两个脚本仅显示
选项hB已启用,无论是否以交互方式运行。这些解决方案的问题是父作为普通用户运行,而子进程通过sudo以root身份运行(它最终将是二进制文件,而不是suid脚本),所以父进程无法杀死它?如果那是"操作不允许"意思是,为什么sudo在通过终端发送击键中断时调用了进程可用?
自然过程是为了避免额外的代码,除非必要 - 即,因为脚本在交互式运行时表现正确,如果可行的话,在非交互式/通过cron运行时简单地应用相同的行为是非常优选的。 / p>
最重要的问题是,在非交互式运行时发出中断(或术语)信号可以做什么,产生与交互运行时发出的中断信号相同的行为?
感谢。非常感谢任何帮助。
答案 0 :(得分:2)
CTRL-C
并发送到 前台进程组 中的所有进程(脚本本身和SIGINT
命令)。 sudo
发送到shell脚本本身,SIGINT
命令将继续运行,并且bash在退出此类场景时不会终止其子项。 要明确向整个流程组发送信号,您可以使用否定的流程组ID 。 对于你的情况,pgid应该是shell脚本的PID,所以试试这样:
sudo
事实证明我对pgid价值的假设是错误的。刚用这个简单的trap 'kill -SIGINT -$$' SIGCHLD
进行了测试:
cron.sh
和#!/bin/bash
set -m
sleep 888 &
sudo sleep 999
看起来像这样:
crontal -l
当cron作业正在运行30 * * * * /root/tmp/cron.sh
输出时,如下所示:
ps
所以 PPID PID PGID SID COMMAND
15486 15487 15487 15487 /bin/sh -c /root/tmp/cron.sh
15487 15488 15487 15487 /bin/bash /root/tmp/cron.sh
15488 15489 15489 15487 sleep 888
15488 15490 15490 15487 sudo sleep 999
15490 15494 15490 15487 sleep 999
(和它的孩子)在一个单独的pgrp中运行而pgid不是sudo
的pid所以我的解决方案(cron.sh
)不起作用。< / p>
然后我认为我们可以解决这个问题:
kill -INT -$$