bash:CTRL-Cと「順番クリーンアップ」の出力が異なります。

bash:CTRL-Cと「順番クリーンアップ」の出力が異なります。

私はこの質問のより良いタイトルを見つけようとしています。私は提案で開いています。

EXITシグナルが受信されると、関数をキャプチャして呼び出すbashスクリプトを作成しました。呼び出されたファイルが存在するときにstop同じ関数を呼び出します。ここにいる:

#!/bin/bash

TAIL_PID=0
CAT_PID=0

DEVICE=/dev/ttyACM0
WDIR=plasma
LOGFILE=$WDIR/$(date +%Y%m%d_%H%M%S.log)
CMDFILE=$WDIR/toDevice

function kill_tail
{
  if [ $TAIL_PID -ne 0 ]
  then
    kill $TAIL_PID
    TAIL_PID=0
    echo "killed tail"
  fi
}

function kill_cat
{
  if [ $CAT_PID -ne 0 ]
  then
    kill $CAT_PID
    CAT_PID=0
    echo "killed cat"
  fi
}

function on_die
{
  echo 't 0' >> $DEVICE
  kill_tail
  kill_cat
  echo "stopped logging"
}
trap on_die EXIT

# mount plasma oven directory if it is not already mounted
mountpoint -q $WDIR || sshfs user@server:plasma $WDIR    
# see if device is available/wait for device
while [ ! -c $DEVICE ]
do
  sleep 1
done
echo "Found controller"

# stop output, remove start and stop files
echo 't 0' >> $DEVICE
rm $WDIR/start $WDIR/stop

# outer loop
while [ 1 ]
do
  while [ ! -f $WDIR/start ]
  do
    sleep 1
  done
  rm $WDIR/start

  # stop output
  echo 't 0' >> $DEVICE

  # pass commands to device
  # but clear existing commands first
  > $CMDFILE
  tail -f $CMDFILE > $DEVICE &
  TAIL_PID=$!
  echo "tail PID = " $TAIL_PID

  # start logging
  cat $DEVICE >> $LOGFILE &
  CAT_PID=$!
  echo "cat PID = " $CAT_PID

  # start output
  echo 't 1000' >> $DEVICE
  echo "started logging to " $LOGFILE

  while [ ! -f $WDIR/stop ]
  do
    sleep 1
  done
  rm $WDIR/stop

  on_die

done # end of outer loop

このスクリプトを実行すると、Iまたはingにtouch start基づいて出力が生成されます。CTRL-Ctouch stopCTRL-C

killed tail
killed cat
stopped logging

以降の出力は次のとおりですtouch stop

killed tail
killed cat
stopped logging
./mountPlasma: line 93: 21200 Terminated              tail -f $CMDFILE > $DEVICE
./mountPlasma: line 93: 21201 Terminated              cat $DEVICE >> $LOGFILE

なぜ?同じ関数を呼び出すと、両方の呼び出しに同じ出力が必要ですon_die。出力は、93行目で2つの追加メッセージが発行されたことを示していますdone # end of outer loop(この記事では、数行を削除する必要があるため、行番号が上記のコードと正確に一致しません)。

私はbashの経験がないので、これが副作用があるかどうかわかりません。彼は予想通り殺されたtailcat

ベストアンサー1

をクリックすると、Ctrl-C実行中のスクリプトがSIGINTを取得し、子に伝播し、「一般」終了時にデフォルトのSIGTERM(を使用して登録された関数からEXIT)を送信します。

Ctrl-Cつまり、停止条件の違いが大きい。どちらの場合も、終了ハンドラ関数が呼び出されますが、実際のイベントはまったく異なります。 SIGINTの場合、子プロセスはそのプロセスによって終了されます(または少なくとも終了することができます)。そしてスクリプトを解釈するシェルは、この状態の変化を報告する機会はあまりありません。それ以外の場合はキャプチャされます。信号灯終了したプログラムから情報メッセージを表示します。

これで、解釈シェルに確認するのに十分な時間があれば、SIGINTからメッセージを取得することもできます(より正確には、シェルが去るとは思わないからです)。ゾンビプロセスこの場合、--報告状況)対応するサブプロセス。 1つのアプローチは、wait組み込み関数を使用して、すべてのプロセスまたは指定されたプロセスが状態を変更するまで積極的に待機することです。シャットダウンハンドラを爆破すること(他のハンドラを使用するなどsleep)もオプションですが、これは実際にはインタプリタのシャットダウンとサブチェックの間の競合状態であることに注意してください(したがって、ブロックはwaitこれを行う安全な方法です)。

おすすめ記事