如何将 stdout 保存到文件、stderr 保存到文件、stdout+stderr 保存到文件以及将 stdout + stderr 保存到终端,就像 shell 脚本的正常情况一样

如何将 stdout 保存到文件、stderr 保存到文件、stdout+stderr 保存到文件以及将 stdout + stderr 保存到终端,就像 shell 脚本的正常情况一样

如何将 stdout 保存到一个文件,将 stderr 保存到另一个文件,将 stdout+stderr 保存到第三个文件,并像 shell 脚本一样将 stdout + stderr 保存到终端?

我在其他地方找到了这个:

exec > >(tee std_out) 2> >(tee err_out >&2)
ls # Should got to std_out
fsdfs # Command not found goes to err_out

这真的很接近。如果我运行,bash test.sh 2>&1 | tee output那么它可以工作,但我无权访问我的脚本的运行方式。这是一个cid系统。我需要能够使用 exec 从脚本内部执行“组合输出”。

我正在创建一个 CI/CD 库,但我无法知道客户将使用该库做什么,因此我想考虑每个用例。

答案1

简单地扩展你的方法:

exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)

标准错误将被写入名为 的文件stderr,标准输出为stdout,标准错误和标准输出也将被写入控制台(或exec运行时两个文件描述符指向的任何内容)和stdall
tee -a(append) 是必需的,以防止被开始写入的stdall第二个数据覆盖。tee

注意命令其中执行重定向是相关的:第二个进程替换受到第一个重定向的影响,即它发出的错误将被发送到>(tee -a stderr stdall).当然,您可以将第二个进程替换的标准错误重定向到 以/dev/null避免这种副作用。在标准错误之前重定向标准输出也会将每个错误发送到stdoutstdall

由于 Bash 进程替换中的命令被执行异步地,无法保证它们的输出将按照生成的顺序显示。更糟糕的是,标准输出和标准错误的片段最终可能出现在同一行。

答案2

$0您的脚本可以通过(通过设置和检查环境变量以避免无限递归)自行运行,而不是依赖 bash 的> >(...)构造,而 IMLE 的构造是反复无常且不可靠的。

if [ "$REDIRECTED" != 1 ]; then
        export REDIRECTED=1
        set -o pipefail
        { { "$0" | tee stdout >&3; } 2>&1 | tee stderr; } 3>&1 | tee stdboth
        exit
fi
# rest of your script here

由于tee不使用行缓冲(也不能使用 强制这样做stdbuf(1)),因此最终输出中将不考虑写入 stdout 和 stderr 的数据顺序。对于使用完全缓冲并同时写入 stdout 和 stderr 的命令,即使行缓冲也tee无济于事,更糟糕的是,您可能会得到一半 stdout 和一半 stderr 的输出行。

我认为仅使用 shell 语言和现成的命令行实用程序无法解决此问题。

答案3

我正在创建一个 CI/CD 库,但我无法知道客户将使用该库做什么,因此我想考虑每个用例。

鉴于这种情况,我质疑 bash 是否需要处理输出。理想情况下,在这种情况下,您需要对输出添加时间戳并为其提供标准输出类型的 id,并且应用程序应该决定如何处理消息。

相关内容