使用 bash,如何将 stderr 和 stdout 复制到日志文件并将它们显示在控制台上?
我想使用 exec 在脚本本身中执行此操作。
我尝试过
exec &>> log.out
echo "This is stdout"
echo "This is stderr" >&2
但上面的内容在控制台上没有打印任何内容。我怎样才能在 bash 中实现这一目标?
答案1
您正在寻找tee
.
man tee
详情请参阅。
要将其与 结合起来exec
,您必须使用流程替代。 (man bash
详情请参阅。)
exec &> >(tee log.out)
echo "This is stdout"
echo "This is stderr" >&2
答案2
我知道这是一篇旧文章,但为什么不这样做呢?
echo "hi" >> log.txt #stdout -> log
echo "hi" | tee -a log.txt #stdout -> log & stdout
echo "hi" &>> log.txt #stdout & stderr -> log
echo "hi" |& tee -a log.txt #stdout & stderr -> log & stdout
当然,如果你想要标准输出,你可以定期打印。
您可以使用您希望的任意流组合来执行此操作,只需使用这两个基本命令即可。
我知道我来到这里并没有得到一个易于理解/实施的答案,希望这对其他人有帮助。
顺便说一句,对于像我以前那样的菜鸟来说,所有命令tee
所做的就是将 stdin 输入输出到 stdout 和指定为后续参数的文件。-a
代表追加,因此每次使用该命令时都不会覆盖该文件。如果您还有其他问题,我发现这成为快速学习 bash 非常有用的资源。
答案3
你可以做:
: > log # empty log file if necessary
{ { {
...the script
} 3>&- | tee -a log >&3 3>&-
exit "${PIPESTATUS[0]}"
} 2>&1 | tee -a log >&2 3>&-
} 3>&1
exit "${PIPESTATUS[0]}"
您也可以将其写为:
: > log # empty log file if necessary
exec 2> >(tee -a log >&2) > >(tee -a log)
...the script
但是因为 bash 不等待那些以>(...
) 开头的进程,所以有时会在命令返回后向终端输出一些东西,这会产生令人讨厌的效果,如果终端“tostop”属性,这可能会产生更糟糕的效果(例如默默地丢弃该输出)已开启。
无论如何,通过stdout
在两个解决方案中创建管道,并且由于两个命令独立输出输出和错误消息,这将影响输出缓冲以及输出和错误消息的显示顺序。
答案4
另一种方法是在函数内使用重定向。
#!/bin/bash
function1 () {
echo 'STDOUT from function 1'
echo 'STDERR from function 1' >&2
}
function2 () {
echo 'STDOUT from function 2'
echo 'STDERR from function 2' >&2
}
function3 () {
echo 'STDOUT from function 3'
echo 'STDERR from function 3' >&2
}
main() {
function1
function2
function3
}
main 2>&1 |tee log.txt
这里我们有一个main
调用所有其他函数的函数。现在将STDOUT
and函数STDERR
重定向main
到tee
.