私はこの質問のより良いタイトルを見つけようとしています。私は提案で開いています。
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-C
touch stop
CTRL-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の経験がないので、これが副作用があるかどうかわかりません。彼は予想通り殺されたtail
。cat
答え1
をクリックすると、Ctrl-C
実行中のスクリプトがSIGINTを取得し、子に伝播し、「一般」終了時にデフォルトのSIGTERM(を使用して登録された関数からEXIT
)を送信します。
Ctrl-C
つまり、停止条件の違いが大きい。どちらの場合も、終了ハンドラ関数が呼び出されますが、実際のイベントはまったく異なります。 SIGINTの場合、子プロセスはそのプロセスによって終了されます(または少なくとも終了することができます)。そしてスクリプトを解釈するシェルは、この状態の変化を報告する機会はあまりありません。それ以外の場合はキャプチャされます。信号灯終了したプログラムから情報メッセージを表示します。
これで、解釈シェルに確認するのに十分な時間があれば、SIGINTからメッセージを取得することもできます(より正確には、シェルが去るとは思わないからです)。ゾンビプロセスこの場合、--報告状況)対応するサブプロセス。 1つのアプローチは、wait
組み込み関数を使用して、すべてのプロセスまたは指定されたプロセスが状態を変更するまで積極的に待機することです。シャットダウンハンドラを爆破すること(他のハンドラを使用するなどsleep
)もオプションですが、これは実際にはインタプリタのシャットダウンとサブチェックの間の競合状態であることに注意してください(したがって、ブロックはwait
これを行う安全な方法です)。