キャプチャ信号を送信すると、POSIXシェルでは「読み取り」が返されますが、Bashでは返されないのはなぜですか?

キャプチャ信号を送信すると、POSIXシェルでは「読み取り」が返されますが、Bashでは返されないのはなぜですか?

シグナルを待ってバックグラウンドでアイドル状態のシェルスクリプトを作成しようとしています。スクリプトがユーザー入力を許可しないため、read待っている間にスクリプトを無期限にブロックしたいと思います。

Bashでは、次のコードは期待どおりに動作しているように見え、SIGUSR1が受信されるたびに「信号」を出力します。

#!/bin/bash
trap "echo signal" SIGUSR1
read
$ ./test
signal
signal
...

ただし、BusyBox ashを使用して実行している場合は、#!/bin/shSIGUSR1を送信するとプログラムが終了します。

#!/bin/sh
trap "echo signal" SIGUSR1
read
$ ./test
signal
$

read標準入力からEOFまたはIFSを読み込んだ後にのみ返すべきではありませんか?この場合、そのようなことは起こりません。それで返される原因は何ですか?

答え1

DashとBusyBoxはPOSIX仕様に準拠しているため、信号がreadすぐに終了する可能性があります。 Bash は、次の場合を除き、そうではありません。POSIXモード。このセクションは次のとおりです。シグナル状態

シェルがユーティリティのフォアグラウンドコマンドの実行が完了するのを待っている間にトラップセット信号が受信されると、その信号に関連するトラップはフォアグラウンドコマンドが完了するまで実行されません。

read一つでもない特殊内蔵、同じプロセス内で実行しても「フォアグラウンドコマンドで実行されるユーティリティ」です。これはトラップを実行し、実行を続行するbash動作を排除しますread

このセクションは次のとおりです。実行環境ユーティリティの実行時に信号がどのように機能するかを明確にしました(非特殊組み込み機能も含む)。

ユーティリティがシェルスクリプトの場合、シェルによってキャプチャされたトラップはデフォルト値に設定され、シェルで無視されるトラップはユーティリティを無視に設定する必要があります。ユーティリティがシェルスクリプトでない場合、トラップ操作(デフォルトまたは無視)は次のように設定する必要があります。ユーティリティの適切な信号処理タスクにマッピング

組み込みスクリプトはシェルスクリプトではありませんが、まだスクリプトを実行しているシェルの一部として実行されているため、最初の句を適用できます。ただし、どちらの動作も、ユーティリティが親トラップを実行することを許可しません。可能な唯一の動作は、read信号を無視、ブロック、またはすぐに返すことです。説明read信号への言及がないため、標準信号に対するマスクの変更は許可されず、無視できません。read間違いなく完了するまで信号を遮断できます(プログラムは内部目的のために一時的に信号を遮断できます)。しかし、これはread入力を待っている間にSIGINTをブロックしたくない風と衝突します(Occamのかみそりの刃はそうすることは意味がないと言います)。 SIGINTの場合、これは動作です。したがって、readSIGUSR1(mkshが機能する方法)で何もしないことは、技術的に規制に準拠することができますが、合理的な行動だとは思わない。

DashとBusyBoxはPOSIXと完全に互換性がありません。信号によって中断されると、両方(Ubuntu 22.04ベース)$?1に設定されます。read終了ステータス

信号の受信によって終了するコマンドは、128を超える終了状態を報告する必要があります。

(実際にはATT kshが256+信号値であることを除いては128+信号値です。)

関連情報