脚本目标:该脚本被调用为./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 $$
}
答案1
我无法重现 seg 错误,但我猜测向自己发送 SIGTERM 将重新调用 Killemall 函数,该函数将发送 SIGTERM,这将调用 Killemall ...
实际上,您不需要执行任何操作来终止脚本。该函数killemall
被调用,完成后脚本将退出。如果需要,您可以在函数末尾添加exit 0
,使其更加清晰。