我正在尝试找到一种方法将命令的输出保存到变量,但也可以实时打印它。我最初找到了一个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)