将 stdout 和 stderr 复制到日志文件并将它们留在脚本本身的控制台上

ada*_*shr 16 bash stderr exec

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

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

我试过

exec &>> log.out

echo "This is stdout"
echo "This is stderr" >&2
Run Code Online (Sandbox Code Playgroud)

但是上面的内容在控制台上没有打印任何内容。我怎样才能在 bash 中实现这一点?

H.-*_*itt 14

您正在寻找tee.

详情请参阅man tee

要将其与 结合exec,您必须使用进程替换。(详情请参阅man bash。)

exec &> >(tee  log.out)
echo "This is stdout"
echo "This is stderr" >&2
Run Code Online (Sandbox Code Playgroud)

  • 这合并了 stdout 和 stderr ,并且可能会产生与我的答案中提到的相同的副作用。 (3认同)

use*_*583 6

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

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
Run Code Online (Sandbox Code Playgroud)

当然,如果你想要标准输出,你可以定期打印。

您可以使用您希望的任何流组合来执行此操作,只需使用这两个基本命令即可。

我知道我来到这里并没有得到一个易于理解/实施的答案,希望这会对正在挣扎的其他人有所帮助。

顺便说一句,对于像我以前的自己一样的菜鸟,所有tee命令所做的就是将 stdin 输入输出到 stdout 和指定为后续参数的文件。-a代表追加,因此您不会在每次使用该命令时覆盖文件。如果您还有其他问题,我发现是快速学习 bash 的非常有用的资源。

  • 感谢您的贡献。另一方面,我完全忘记了我想要做什么:-) (2认同)
  • 为什么?因为您必须[将 `tee` 添加到文件中的每个命令](https://unix.stackexchange.com/questions/61931/redirect-all-subsequent-commands-stderr-using-exec)。 (2认同)

Sté*_*las 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]}"
Run Code Online (Sandbox Code Playgroud)

你也可以把它写成:

: > log # empty log file if necessary
exec 2> >(tee -a log >&2) > >(tee -a log)

...the script
Run Code Online (Sandbox Code Playgroud)

但是因为 bash 不等待那些以>(...)开头的进程,所以有时会在命令返回后向终端输出一些东西,如果终端“tostop”属性,这可能会产生更严重的影响(比如默默地丢弃该输出)正在。

在任何情况下,通过stdout在两种解决方案中创建管道,并且由于两个命令独立输出输出和错误消息,这将影响输出缓冲以及显示输出和错误消息的顺序。


Kan*_*han 5

另一种方法是在函数内使用重定向。

#!/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
Run Code Online (Sandbox Code Playgroud)

这里我们有一个main调用所有其他函数的函数。现在将STDOUTandSTDERR函数重定向maintee.

  • 恕我直言,这是最干净的方法,至少对于简单的情况来说是这样。谢谢。 (2认同)