将stdout和stderr复制到日志文件,并将其保留在脚本本身内的控制台上


11

使用bash,如何将stderr和stdout复制到日志文件,并同时在控制台上显示它们?

我想使用exec在脚本本身中执行此操作。

我尝试过

exec &>> log.out

echo "This is stdout"
echo "This is stderr" >&2

但是以上内容在控制台上什么也没打印。我如何在bash中实现这一目标?


对于StackOverflow上的类似问题,有一个高度赞同的答案,它可以非常彻底地回答该问题。stackoverflow.com/a/692407/208257
Dan Burton,

Answers:


10

您正在寻找tee

有关man tee详细信息,请参见。

要与之结合exec,必须使用流程替代。(有关man bash详细信息,请参阅。)

exec &> >(tee  log.out)
echo "This is stdout"
echo "This is stderr" >&2

我已经看过了。这样做exec 2>&1 | tee -a log.out只是在控制台上打印,没有在日志文件中。也许我使用的语法不正确?
2013年

@adarshr请仔细检查您的代码。我已经tee结合进程替代进行了撰写。
H.-Dirk Schmitt

1
但是,这合并了stdout和stderr,并且可能具有与我的回答中提到的相同的副作用。
斯特凡Chazelas

@StephaneChazelas查看问题中的示例代码-这是OP的意图。
H.-Dirk Schmitt 2013年

我的意思是合并,现在脚本的错误转到stdout。因此the-script | wc -l,例如,如果有人这样做,那也将计算错误行,并且您将看不到错误。
斯特凡Chazelas

5

你可以做:

: > 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在两个解决方案中都使用管道,并且由于两个命令独立地输出输出和错误消息,这将影响输出缓冲以及输出和错误消息的显示顺序。


我认为您的第二个发球区缺少对stderr的重定向。应该是:tee -a log >&2 3>&-
richvdh 2014年

5

我知道这是旧帖子,但为什么不这样做呢?

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代表append,因此您不必每次使用命令都覆盖文件。如果您还有其他问题,我认为对于快速学习bash是非常有用的资源。


1
感谢您的贡献。另一方面,我完全忘记了我想做的事情:-)
adarshr

1
+1给出了多个漂亮且简单的T恤示例。
蒂姆(Tim)

2

完成此操作的另一种方法是在函数内使用重定向。

#!/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调用所有其他函数的函数。现在重定向STDOUTSTDERRmain发挥作用tee


恕我直言,至少在简单情况下,这是最干净的方法。谢谢。
ACK_stoverflow,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.