トラップを使用して終了を確認しました


9

Ctrl+Cユーザーに確認を求める信号をトラップしようとしています。トラッピング部分は正常に動作します。ただし、信号がトラップされると、通常の実行に戻りません。代わりに、スクリプトを終了します。ユーザーがいいえを押したときに実行を再開させる方法。

これが私のコードです

hell()
{
echo "Do you want to quit? Press 1 for yes and 0 for no";
read n;
if [ $n == 1 ]; then
exit 1;
fi
}

trap "hell" SIGINT

find /

回答:


12

何が起こっていますか

Ctrl+ を押すCと、SIGINTシグナルがフォアグラウンドプロセスグループ全体に配信されます。ここでは、findプロセスと呼び出し元のシェルプロセスの両方に送信されます。findすぐに終了することで反応し、シェルはトラップを呼び出すことで反応します。

トラップ内のコードが戻る(つまりexit、を呼び出さない)場合は、シグナルによって中断されたコマンドの後にコマンドが実行されます。ここでは、findコマンドの後にスクリプトの終わりが来るため、スクリプトはとにかくすぐに終了します。しかし、別のコマンドを追加することで、0と1の入力の違いを確認できます。

find /
echo "find returned $?"

あなたがやりたいことをする方法(しかし、おそらくすべきではない)

あなたがやりたいことができます; しかし、私の答えのこの部分は、実際の問題を解決することよりも、シェルプログラミングを発見することに関するものです。

  • 設計上の問題として、再起動可能な信号は、シェルスクリプトが通常そうであるような比較的単純なプログラムで通常期待するものではありません。Ctrl+ Cがスクリプトを強制終了することを期待しています。
  • 以下に示すように、シェルの機能が少し拡張されています。

あなたが殺害を回避したい場合find、あなたはそれを起動する必要があり背景find / &。次に、wait組み込みを使用して、正常に終了するのを待ちます。信号はwait組み込みを中断します。これは、伝播する信号を受信するまでループで実行できます。次にkill、ジョブを強制終了するために使用します。

hell () {
  echo "Do you want to quit? Press 1 for yes and 0 for no"
  read n
  if [ "$n" = 1 ]; then
    # Kill the job if it's running, then exit
    if [ -n "$job_pid" ]; then kill $job_pid; fi
    exit 1
  fi
}

job_pid=
trap "hell" SIGINT

# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
  echo "resuming wait"
done
job_pid=
echo last exit code: $?

シェルのこのアプローチには制限があります。

  • 競合状態があります。ジョブが終了した直後、行の前でCtrl+ を押すと、シグナルハンドラーはkillを試行しますが、プロセスは存在しません(ゾンビとしても、すでに取得しているため)。 IDは別のプロセスで再利用された可能性があります。これはシェルでは簡単に修正できません(おそらくハンドラーを?に設定することで)。Cjob_pid=$jobpidwaitSIGCHLD
  • ジョブからの返却ステータスが必要な場合は、wait $job_pidフォームを使用する必要があります。しかし、「waitシグナルによって中断された」と「ジョブがシグナルによって強制終了された」(または「ジョブがリターンステータス≥128で終了したためにジョブが終了した」と区別することはできませんが、これはシェルの一般的な事実です)プログラミング)。
  • これは、複数のサブジョブにまで及ぶ場合、簡単には拡張されません。ほとんどのシェル実装の基本を超えると、トラップとシグナルの動作が驚くべきことがよくあることに注意してください(kshだけがこれをうまく実行します)。

これらの制限を克服するには、PerlやPythonなどのより洗練された言語を使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.