3

SIGTERM と SIGTSTP をトラップするスクリプトがあります。これは私がメインブロックに持っているものです:

trap 'killHandling' TERM

そして関数で:

killHandling () {
    echo received kill signal, ignoring
    return
}

... SIGINT についても同様です。問題は、ユーザー インターフェイスの 1 つです。スクリプトはユーザーに何らかの入力を求めるプロンプトを表示します。スクリプトが入力を待機しているときに SIGTERM または SIGINT が発生すると、混乱を招きます。その場合の出力は次のとおりです。

Enter something:     # SIGTERM received
received kill signal, ignoring

      # shell waits at blank line for user input, user gets confused
      # user hits "return", which then gets read as blank input from the user
      # bad things happen because of the blank input

次のように、これをよりエレガントに処理するスクリプトを見たことがあります。

Enter something:     # SIGTERM received
received kill signal, ignoring
Enter something:     # re-prompts user for user input, user is not confused

後者を達成するために使用されるメカニズムは何ですか? 残念ながら、スクリプトがユーザーにいくつかのことを要求し、プロンプトの内容はコンテキストに依存するため、トラップ コードを単純に変更して再プロンプトを実行することはできません。また、コンテキスト依存のトラップ関数を記述するよりも優れた方法が必要です。

私はどんな指針にも非常に感謝しています。ありがとう!

4

2 に答える 2

2

これらはそれほど堅牢な方法ではありません。たとえば、最初のトラップの後に CTRL-C を文字として処理する方法に問題がありますが、どちらも定義したユース ケースを処理します。

BASH_COMMAND を使用して、最後のコマンド (読み取りなど) を再実行します。

prompt () {
    read -p 'Prompting: '
}
reprompt () {
    echo >&2
    eval "$BASH_COMMAND"
}
trap "reprompt" INT
prompt

この場合、*BASH_COMMAND* は と評価されread -p 'Prompting: 'ます。次に、コマンドを eval で再処理する必要があります。評価しないと、奇妙な引用の問題が発生する可能性があります。YMMV。

FUNCNAME を使用して、コール スタック内の前の関数を再実行します。

prompt () {
    read -p 'Prompting: '
}
reprompt () {
    echo >&2
    "${FUNCNAME[1]}"
}
trap "reprompt" INT
prompt

この例では、FUNCNAME[1]promptは、スタック内の前の関数である に展開されます。必要に応じて何度でも再帰的に呼び出すだけです。

于 2012-06-09T22:36:27.660 に答える
0

CodeGnome が出した答えは機能しますが、彼が指摘するように、堅牢ではありません。2 番目の control-c は望ましくない動作を引き起こします。コード内の既存の入力検証をより有効に活用することで、最終的に問題を回避しました。したがって、私の割り込み処理コードは次のようになります。

killHandling () {
   echo received kill signal, ignoring
   echo "<<Enter>> to continue"
   return
}

現在、カーソルは空白行でユーザー入力を待機していますが、ユーザーは混乱せず、プロンプトに従って「Enter」キーを押します。次に、スクリプトの入力検証により、無効な入力として扱われる空白行が入力されたことが検出され、ユーザーは何かを入力するように再度求められます。

CodeGnome の提案には今でも感謝しており、そこからいくつかのことを学びました。そして、この回答の投稿が遅れたことをお詫びします。

于 2012-08-21T01:09:59.873 に答える