シグナルハンドラで自分自身を終了するスクリプトが分割エラーを生成するのはなぜですか?

シグナルハンドラで自分自身を終了するスクリプトが分割エラーを生成するのはなぜですか?

スクリプトの対象:スクリプトは、./script.sh cmd1 cmd2 ... cmdnバックグラウンドでコマンドラインから引数として渡されたすべてのコマンドを実行し、すべてのコマンドの実行が完了したことを確認する必要があります。また、SIGTERM信号がスクリプトに送信されたら、上記のすべてのプロセス(cmd1 ... cmdn)を終了してからそれ自体を終了する必要があります。

質問:自動シャットダウンを除いて、すべてが機能しているようですが、理由がわかりません。を試してみましたが、kill $$実行時に。コマンドが関数の内部にあるという事実に関連しているようsegmentation faultですが、コマンドをコメントアウトしてそのままにしておくと後者が機能します。誰かが私が逃したことを説明できますか?killkill $$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

セグメントエラーを再現することはできませんが、SIGTERMを自分に送信すると、Killemall関数を再度呼び出し、SIGTERMを送信してKillemallを呼び出すと推測されます。

実際にスクリプトを終了するために何もする必要はありません。関数killemallが呼び出され、完了するとスクリプトは終了します。必要に応じて、関数の末尾に追加してexit 0より明確にすることができます。

関連情報