Linux shell:将 stderr 和 stdout 通过管道传输到一个文件并同时传输到单个文件(使用 tee?)

Linux shell:将 stderr 和 stdout 通过管道传输到一个文件并同时传输到单个文件(使用 tee?)

我想形成一个管道流,将 stdout 捕获到一个文件,将 stderr 捕获到另一个文件,并将两者都捕获到第三个文件中(因此完整的终端输出也在同一个文件中)

不知怎的像这样:

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

我知道我必须使用 tee,但我搞不懂。你们有解决方案吗?最好使用 Bash/sh...

谢谢您的帮助,我非常感激 !!!

答案1

首先:我不建议您这样做,在单个文件中预先添加带有时间戳和标签(例如 [INFO] 和 [ERROR])的记录消息或仅在两个文件中添加时间戳,从长远来看可能是一个更好、更可靠的想法。同时仍允许您使用 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

相关内容