Linux シェル: stderr と stdout を 1 つのファイルにパイプすると同時に、個別のファイルにパイプする (tee を使用)

Linux シェル: stderr と stdout を 1 つのファイルにパイプすると同時に、個別のファイルにパイプする (tee を使用)

stdout を 1 つのファイルに、stderr を別のファイルにキャプチャし、両方を 3 番目のファイルにキャプチャするパイプ ストリームを形成したいと思います (つまり、完全な端末出力も 1 つのファイルに含まれます)

こんな感じです:

process ----+-- <stdout> --- + --- stdlog.txt 
            |                |
            |                }---- <terminal> --- alllog.txt
            |                |
            \-- <stderr> --- +---- errlog.txt 

tee を使う必要があるのはわかっていますが、方法がわかりません。皆さんは解決策を持っていますか? Bash/sh が望ましいです...

ご協力ありがとうございます、本当に感謝しています!!!

答え1

まず、これはお勧めしませんが、ログに記録されたメッセージの先頭に、タイムスタンプと [INFO] や [ERROR] などのラベルを 1 つのファイルに追加するか、2 つのファイルにタイムスタンプだけを追加する方が、長期的にはおそらくより優れた、より信頼性の高いアイデアです。grep やソートを使用して、必要な他のファイルを作成することもできます。

あなたの問題について: これまでそれをする必要はありませんでしたが、おそらく名前付きパイプを使用する必要があるでしょう。テストされていない bash の例:

# Log one output type
function logger() {
    unique_file="$1"
    common_file="$2"
    # Tee reads from the function's standard input, writes to unique_file, appends to common_file, then outputs what was written
    tee "$unique_file" | tee -a "$common_file"
}

# Call your code's main function to start processing
main > >(logger info_log_file common_log_file) 2> >(logger error_log_file common_log_file >&2)

を使いたくなるかもしれませんexec >"$info_pipe" 2>"$error_pipe"。しかし、そうしないと、ログファイルが利用可能なディスク領域をすべて埋めてしまうループが生成されます。

bash が暗黙的な名前付きパイプをサポートしていない場合 (サポートされるはずですが、サポートされていない環境を見たことがあります)、mkfifo を呼び出して明示的に名前付きパイプを使用する必要があるかもしれませんが、これにはさらに配管が必要です。

# Log one output type
function logger() {
    unique_file="$1"
    common_file="$2"
    # Tee reads from the function's standard input, writes to unique_file, appends to common_file, then outputs what was written
    tee "$unique_file" | tee -a "$common_file"
}

# Setup logging
function prepare() {
    tmp_pipe_dir="$(mktemp -d)"
    error_pipe="$(mkfifo "$tmp_pipe_dir/error")"
    info_pipe="$(mkfifo "$tmp_pipe_dir/info")"
}

function cleanup() {
    rm -rf "$tmp_pipe_dir"
}

prepare
# Start logging, note that logger won't stop on its own. Removing the pipe files should do the trick
logger info_log_file common_log_file <"$info_pipe" &
logger error_log_file common_log_file <"$error_pipe" >&2 &
# Call your code's main function to start processing
main >"$info_pipe" 2>"$error_pipe"
cleanup

関連情報