Por que o script que se mata usando um manipulador de sinal produz uma falha de segmentação?

0

OBJETIVO DO SCRIPT: o script é invocado como ./script.sh cmd1 cmd2 ... cmdn . Ele deve executar em segundo plano todos os comandos passados como argumentos da linha de comando e verificar quando todos terminaram sua execução. Além disso, se o sinal SIGTERM for enviado para o script, ele deve matar todos os processos acima mencionados ( cmd1 ... cmdn ) e depois se matar.

PROBLEMA: Tudo parece funcionar, exceto a autoterminação e não consigo entender por quê. Eu tentei usar kill $$ , mas em tempo de execução eu recebo segmentation fault . Eu estava pensando que o problema estava relacionado ao fato de que o comando kill está dentro de uma função mas, por outro lado, se eu comentar kill $$ e eu deixar o comando kill ${PIDAR[*]} , o último trabalho. Alguém poderia me explicar o que estou perdendo?

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

Obrigado

SOLUÇÃO: como user18197 apontou, o problema está chamando kill $$ . De fato, como a página kill man reporta:

The default signal for kill is TERM

Em seguida, a cada invocação de kill $$ , o script chamava o manipulador killemall , que por sua vez estava invocando novamente kill $$ e assim por diante de forma recursiva. Para evitar esse comportamento, podemos remover SIGTERM signal. Como help trap relatórios:

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

O novo corpo da função é:

killemall () {     
   echo $$
   trap - SIGTERM
   kill ${PIDAR[@]}
   kill $$                
} 
    
por ikeDiM 27.04.2018 / 12:06

1 resposta

3

Eu não consegui reproduzir a falha seg, mas estou supondo que enviar SIGTERM para si mesmo irá reinvocar a função killemall, que enviará SIGTERM, que invocará o killemall ...

Na verdade, você não precisa fazer nada para encerrar seu script. A função killemall é chamada e quando isso é feito, o script será encerrado. Você pode adicionar um exit 0 no final da função para torná-lo mais claro, se quiser.

    
por 27.04.2018 / 12:22