0

SCRIPT GOAL: the script is invoked as ./script.sh cmd1 cmd2 ... cmdn. It should executes in background all the commands passed as arguments from the command line and check when all of them have finished their execution. Furthermore if the SIGTERM signal is send to the script it should kill all the aforemoentioned processes (cmd1 ... cmdn) and then kill himself.

PROBLEM: All seem working except the autotermination and I can't figure out why. I tried to use kill $$ but at runtime I get segmentation fault. I was thinking that the problem was related to the fact that kill command is inside a function but on the other hand if I comment kill $$ and I leave kill ${PIDAR[*]} command, the latter work. Could somebody explain me what I am missing?

#!/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"  

Thanks

SOLUTION: as user18197 pointed out, the problem is calling kill $$. Indeed as the kill man page reports:

The default signal for kill is TERM

Then at each kill $$ invocation the script was calling the handler killemall which in turn was invoking again kill $$ and so on recursively. To avoid this behaviour we can untrap SIGTERM signal. As help trap reports:

If ARG is absent (and a single SIGNAL_SPEC is supplied) or `-', each specified signal is reset to its original value.

So the new function body is:

killemall () {     
   echo $$
   trap - SIGTERM
   kill ${PIDAR[@]}
   kill $$                
} 
3

I couldn't reproduce the seg fault, but I am guessing that sending SIGTERM to yourself will reinvoke the killemall function, which will send SIGTERM, which will invoke the killemall ...

You actually do not need to do anything to terminate your script. The function killemall is called and when it is done the script will exit. You can add an exit 0 at the end of the function to make it more clear if you want.

  • A program that handles sigint and then dies is usually expected to kill itself by sigint, see for example: gnu.org/software/libc/manual/html_node/… – muru Apr 27 '18 at 10:34
  • AFAIK, that part is handled by the shell, bash in this case. – user18197 Apr 27 '18 at 10:40
  • @user18197 not if you simply exit 0 in the trap handler. – muru Apr 27 '18 at 10:44
  • 1
    @ikeDiM removing the trap handler using trap "" SIGINT and then kill the script. – muru Apr 27 '18 at 10:59
  • 1
    @ikeDiM oh, sorry, I for some reason during the entire conversation I kept saying sigint instead of sigterm. What I mean it is something like: killemall () { trap '' SIGTERM; kill ${PIDAR[@]}; kill $$; } – muru Apr 27 '18 at 11:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.