将命令的输出保存到变量并在不使用 tee 的情况下打印?

将命令的输出保存到变量并在不使用 tee 的情况下打印?

我正在尝试找到一种方法将命令的输出保存到变量,但也可以实时打印它。我最初找到了一个tee似乎可行的例子;

VARIABLE=$(./build.sh | tee /dev/tty)

然而,问题是,如果我在具有虚拟控制台(即 git hub 操作)的系统上运行它,我会收到错误tee: /dev/tty: No such device or address。我只是想找到一种方法将输出保存到变量并实时进行正常打印(即就像 echo、printf 等)

答案1

使用的问题/dev/tty是它假设 stdout 最初附加到 tty - 这不一定是 GitHub Actions 所演示的那样。如果您将脚本的标准输出重定向到其他地方(例如日志文件),这也会是一个问题。

您想要传递给 tee 的是进程替换之前的 stdout(位$(...)) - 进程替换采用 stdout 来捕获输出。 Bash 和其他 shell 能够根据您的用例操作文件描述符:

exec 3>&1  # Open FD 3 as a duplicate of stdout (fd 1)
# Run ./build.sh but make sure it does not have FD 3 open and tee to FD 3
VARIABLE=$(./build.sh 3>&- | tee /dev/fd/3)
exec 3>&-  # Close FD 3

这样做允许在脚本外部操作脚本的标准输出(重定向到记录器或 /dev/null 等),从而保留 WRT 标准输出的正确行为。

正如 @SOUser 在评论中指出的,将脚本的输出写入文件时存在问题。问题是tee /dev/fd/3打开文件时会截断文件,丢弃已写入其中的任何内容。尝试解决这个问题tee -a /dev/fd/3会导致更奇怪的行为——要捕获的线路由于某种原因完全丢失。

解决方案是写入管道而不是文件,因此不要./script > test.log使用./script | cat > test.log。当以这种方式完成时,tee无法截断该文件,因为它没有附加到该文件 - 它附加到一个cat无法截断的管道。

答案2

你可以发球到 stderr:

VARIABLE=$(./build.sh | tee /dev/stderr)

相关内容