为什么使用信号处理程序杀死自身的脚本会产生分段错误?

为什么使用信号处理程序杀死自身的脚本会产生分段错误?

脚本目标:该脚本被调用为./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,使其更加清晰。

相关内容