Bashは 'select'ループが実行されたときにSIGINTトラップを無視します。

Bashは 'select'ループが実行されたときにSIGINTトラップを無視します。

選択ループで「トラップ」を使用すると、つまりオプションが表示されている間にCTRL + Cを押して中断しようとすると、端末に^ Cのみが印刷されます。スクリプトから「トラップ」を削除すると正常に終了します。つまり、Ctrl + Cを使用できます。

私はこれを2つの異なるバージョンのbash(CentOSに付属のバージョンとFedoraに付属のバージョン)でテストしましたが、Fedoraのバージョン(4.4.23(1)-release)に問題があります。 CentOSに付属のBashバージョン4.2.46(2)リリースは正常に動作しているようです。また、端末でローカルにテストし、SSH経由でリモートでテストしました。問題は常にFedoraにあります。

私が言っていることを確認するためにコードを投稿します。

これはうまくいきません。

#!/bin/bash

trap exit SIGINT

select opt in One Two Three; do
        break
done

完全な「トラップ終了SIGINT」行を削除すると、問題なくCTRL + Cを使用でき、正しく機能します。

この問題を解決またはバイパスする方法についてのアイデアはありますか?

ベストアンサー1

この問題を解決またはバイパスする方法についてのアイデアはありますか?

--posixoptionsを使用するか、一時的にposixモードをオンにすると、それをバイパスできます set -o posix

set -o posix
select opt in foo bar baz; do
    echo "opt=$opt"
done
set +o posix

この動作の説明を表示するには確認できます。zread()組み込み関数で使用される関数read(bashから内部的に呼び出されることもありますselect):

  while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
    /* XXX - bash-5.0 */
    /* We check executing_builtin and run traps here for backwards compatibility */
    if (executing_builtin)
      check_signals_and_traps ();   /* XXX - should it be check_signals()? */
    else
      check_signals ();

何らかの特別な理由により、組み込み関数が明示的に呼び出されたときにのみ設定され、によって呼び出されるときは設定されませんexecuting_builtin。これはバグのように見え、意図的なものではありません。readselect

posixモードで実行すると、信号は無効になりますread。この場合、zreadintr()呼び出されるのとは異なり、zread()中断されたシステムコールはトラップ実行後に再度呼び出されません。read(2)バラよりbuiltins/read.def:

      if (unbuffered_read == 2)
        retval = posixly_correct ? zreadintr (fd, &c, 1) : zreadn (fd, &c, nchars - nr);
      else if (unbuffered_read)
        retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1);
      else
        retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c);

Bashの「restart」組み込みコマンドのread詳細ここ

おすすめ記事