脚本目标:脚本被调用为./script.sh cmd1 cmd2 ... cmdn
. 它应该在后台执行从命令行作为参数传递的所有命令,并检查所有命令何时完成执行。此外,如果 SIGTERM 信号被发送到脚本,它应该杀死所有前面提到的进程(cmd1 ... cmdn
)然后杀死自己。
问题:除了自动终止之外,一切似乎都在工作,我不知道为什么。我尝试使用kill $$
,但在运行时我得到segmentation fault
. 我在想问题与kill
命令在函数内部有关,但另一方面,如果我发表评论kill $$
并离开kill ${PIDAR[*]}
命令,则后者起作用。有人可以解释一下我缺少什么吗?
#!/bin/bash
# signal handler
killemall () {
echo $$
kill ${PIDAR[*]}
kill $$ # implicated line
}
PIDAR=() # pid array
STAR=() # process state array
# execute processes in bg and save their pid
for i in "$@" ; do
$i &
PIDAR+=($!)
done
trap 'killemall' SIGTERM
terminated=1 # flag to indicate when all processes are terminated
while sleep 1 && [ $terminated -eq 1 ]; do
for (( i=0; i<${#PIDAR[*]}; i++ )); do
STAR[$i]=$(ps hp ${PIDAR[$i]} | awk '{ print $3 }')
if [ -z ${STAR[$i]} ]; then
terminated=0
else terminated=1
fi
echo "Process state ${PIDAR[$i]}:${STAR[$i]}" | tee -a logg
done
done
echo "All processes are terminated"
谢谢
解决方案:正如 user18197 指出的那样,问题出在调用kill $$
. 确实如kill
手册页报告的那样:
kill 的默认信号是 TERM
然后在每次kill $$
调用时,脚本都会调用处理程序,而处理程序 killemall
又会再次调用kill $$
,以此类推。为了避免这种行为,我们可以解开SIGTERM
信号。据help trap
报道:
如果 ARG 不存在(并且提供了单个 SIGNAL_SPEC)或“-”,则每个指定的信号都将重置为其原始值。
所以新的函数体是:
killemall () {
echo $$
trap - SIGTERM
kill ${PIDAR[@]}
kill $$
}
我无法重现 seg 错误,但我猜向自己发送 SIGTERM 将重新调用 killemall 函数,该函数将发送 SIGTERM,这将调用 killemall ...
您实际上不需要做任何事情来终止您的脚本。该函数
killemall
被调用,完成后脚本将退出。如果需要,您可以在函数末尾添加一个exit 0
以使其更清晰。