Bash:次のパイプの「no-op」によって「ティー」がブロックされました。

Bash:次のパイプの「no-op」によって「ティー」がブロックされました。
  • tee標準出力がno-op()コマンドにパイプされると、何も印刷されず、:ファイルサイズは0です。
  • tee標準出力をにパイプすると、catすべてが正しく印刷され、ファイルサイズが0よりも大きくなります。

以下はこれを示すコード例です(スクリプトの最初の入力パラメータによる条件付き)。

#!/usr/bin/env bash

log_filepath="./log.txt"
[ -f "$log_filepath" ] && { rm "$log_filepath" || exit 1 ; }

fail_tee="$1"

while IFS= read -r -d $'\n' line ; do
    printf "%s%s\n" "prefix: " "$line"  | \
    tee -a "$log_filepath"              | \
    {
        if [ -n "$fail_tee" ]; then
            # Nothing is printed to stdout/terminal
            # $log_filepath size is ZERO.
            : # do nothing. 
        else
            # Each line in the input is prefixed w/ "prefix: " and sent to stdout
            # $log_filepath size is 46 bytes
            cat
        fi
    }
done <<'EOF'
1
23
456
7890
EOF

その後に説明がありますように。
no-opコマンドに対する私の期待は、出力がファイルに送信されるのを:妨げてはならないということです。tee

ベストアンサー1

:inはまだシェルで設定されたパイプの読み取り端を保持するプロセスtee ... | :で、もう一方は書き込みteeです。すぐに終了するため、:パイプからデータを読み取ることができません。 (パイプラインが同時に作業を実行するには、シェルは単にno-opを処理するためであっても、パイプラインの各部分に対して新しいプロセスを作成する必要があります。:あなたの例では、プロセスはif最後のステートメントを実行します。:組み込み関数「実行」した後、最終的に終了します)。

一般的な動作は、パイプリーダーが終了したとき(読み取り側のファイル記述子が閉じる)、書き込み機が次の書き込み時にSIGPIPE信号を受信して​​終了するようにすることです。

これは、パイプラインの右側が終了すると左側も終了し、潜在的に長い操作が無駄に続かないことを意味するため、一般的に望むものです。または(悪い場合)、データがどこに行くかがないため、書き込みを許可しないブロックされたパイプに無力に書き込みを試みます。

tee例外はないようだからPOSIX仕様;最も近い部分には、ファイルオペランドへの書き込みエラーが記載されています。

正常にオープンされたファイルオペランドへの書き込みが失敗した場合、正常にオープンされた他のファイルオペランドと標準出力への書き込みは続行する必要がありますが、終了状態はゼロではありません。

SIGPIPEが無視されると、テストされた実装は引き続き実行され、次に呼び出しからEPIPEエラーが返されますwrite()

GNU coreutilsバージョンには、書き込みに失敗したときに実行する操作を制御するオプションがありますtee-p--output-error

指定されていない場合、デフォルトの操作は--output-errorパイプへの書き込み中にエラーが発生した場合は直ちに終了し、非パイプライン出力への書き込み中にエラーを診断することです。

シャットダウン方法はSIGPIPEを介したものであるため、teeシグナルを無視したものから開始しても終了しません。

デフォルトモードは、シャットダウンする他のオプションとは異なり、「パイプラインではなく出力を書き込んでいる間のエラー診断」-pです。warn-nopipe後ろでは、SIGPIPE シグナルも無視し、パイプへの書き込み試行を停止します。

したがって、少なくともGNUバージョンでは、tee -p ... | ...これを使用してパイプリーダーがシャットダウンしたときにシャットダウンするのを防ぎます。あるいは、たとえば、ブラックホールを模倣するようにプログラムを右側に配置することもできますcat > /dev/null(まだ表示されています)。そして取得するすべてを記録しますが、カーネルは最終的に記録されたデータを無視します/dev/null。)

おすすめ記事