stdinを関数にパイプすると、分割エラー出力が抑制されます。なぜ?

stdinを関数にパイプすると、分割エラー出力が抑制されます。なぜ?

バイナリを実行する関数を定義しましょう。

function execute() { ./binary; }

次に、テキストファイルを最初の関数にパイプする2番目の関数を定義します。

function test() { cat in.txt | execute; }

binarysegfaultと競合する場合、testCLIから呼び出すと戻りコードが発生します139が、「segfault」エラーは端末に印刷されません。

直接呼び出しを定義すると、test「セグメントエラー」が出力されます。binary

function test() { cat in.txt | ./binary; }

stdin を入力せずに呼び出しを定義すると、execute次のように印刷されます。

function test() { execute; }

in.txt最後にパイプを通さずに直接リダイレクトする場合executeにも印刷されます。

function test() { execute <in.txt; }

これは Bash 4.4 でテストされました。なぜそんなことですか?

ベストアンサー1

この診断メッセージは対話型シェルによって生成されます。職業管理システムは、ユーザーの利益のために基本プログラムがクラッシュしたために発生しません。シェル関数をパイプするときサブシェル関数を実行するために作成され、サブシェルはユーザー側とは見なされません。関数が正常に呼び出されると、元のシェルで実行され、メッセージが印刷されます。

現在のシェルでジョブ制御を無効にすることでこれをテストできます。

set +m

その後、./binaryもう一度実行してください。今何も印刷されません。ジョブ制御の再活動化を使用してくださいset -m

単純なサブシェルでも同じ効果があります。

( : ; ./binary )

診断情報は印刷されません(サブシェル除去の最適化を防ぐために2つのコマンドが必要です)。管路出るこの関数も同じことをします。

ジョブ制御はサブシェルで無効になり、手動で有効にしても静かになります。これはシステムの不幸な欠陥です。非対話型シェルでは、メッセージは対話型シェルの他のすべての場所にあるため、常に異なるメカニズムを介して報告されます。


診断内容を印刷することが重要な場合は、関数の代わりにスクリプトを作成して、その内容を常に含めることができます。パイプラインで関数を使用しているため、とにかく関数が必要な操作を実行できないため、これを行うにはかなりの費用がかかりません。


私はこれが間違いだと言いたくありません。このように振る舞う一つの考えられる理由は次のとおりです。コマンドの置き換え$(...)サブシェルも実行するのは適切に機能します。

foo=$(echo|test)

fooパイプラインエラーが原因でnull拡張が発生するように診断メッセージを保存しないでください。別のアプローチは、意図的に診断メッセージを一時的に表示しないことです。

おすすめ記事