使用exec重定向所有后续命令的stderr


43

我有一个bash文件,我需要将所有输出重定向到一个文件,调试日志以及终端。我需要将stdout和stderr都重定向到调试,并在脚本中将其记录为所有命令。

我不想为2>&1 | tee -a $DEBUG文件中的每个命令添加内容。我可以忍受| tee -a $DEBUG

我记得有一种方法可以这样做exec 2>&1

目前,我正在使用类似以下内容的东西:

#!/bin/bash
DEBUGLOG=/tmp/debug
exec 2>&1
somecommand | tee -a $DEBUGLOG
somecommand2 | tee -a $DEBUGLOG
somecommand3 | tee -a $DEBUGLOG

但它不起作用。有没有人有解决方案/可以解释原因?


1
在某些shell |&2>&1 |,它充当的快捷方式,至少稍微方便一些。
凯文

Answers:


39

至于一次重定向大量命令的解决方案:

#!/bin/bash
{
    somecommand 
    somecommand2
    somecommand3
} 2>&1 | tee -a $DEBUGLOG

为什么原始解决方案不起作用:exec 2>&1会将标准错误输出重定向到Shell的标准输出,如果您从控制台运行脚本,它将成为控制台。命令上的管道重定向将仅重定向命令的标准输出。

从的角度来看somecommand,其标准输出进入与之连接的管道tee,标准错误进入与外壳程序标准错误相同的文件/伪文件中,您可以将其重定向到外壳程序的标准输出,即控制台,如果您从控制台运行程序。

一种真正的解释方式是查看实际发生的情况:

如果从终端运行外壳程序的原始环境,则可能如下所示:

stdin -> /dev/pts/42
stdout -> /dev/pts/42
stderr -> /dev/pts/42

将标准错误重定向到标准输出(exec 2>&1)后,您...基本什么都不会更改。但是,如果将脚本的标准输出重定向到文件,则最终会遇到如下环境:

stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /dev/pts/42

然后将shell标准错误重定向到标准输出将最终如下所示:

stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /your/file

运行命令将继承此环境。如果运行命令并将其通过管道传输到tee,则命令的环境为:

stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file

因此,您的命令的标准错误仍然存​​在于shell用作其标准错误的地方。

您实际上可以通过查看/proc/[pid]/fdls -l来查看命令的环境:用于还列出符号链接的内容。0这里的文件是标准输入,1是标准输出,2是标准错误。如果命令打开了更多文件(大多数程序都打开了),您还将看到它们。程序也可以选择重定向或关闭它的标准输入/输出和复用012


41

您可以在脚本顶部使用如下所示的exec:

exec > >(tee "$HOME/somefile.log") 2>&1

例如:

#!/bin/bash -

exec > >(tee "$HOME/somefile.log") 2>&1

echo "$HOME"
echo hi
date
date +%F
echo bye 1>&2

给我这样的输出到文件$HOME/somefile.log和终端:

/home/saml
hi
Sun Jan 20 13:54:17 EST 2013
2013-01-20
bye

2
请注意,这使用了bashisms -在其他shell(例如破折号)中可能不起作用。但是由于问题指定了bash,所以+1。
理查德·汉森

8
@RichardHansen,进程替换是ksh而不是bash引入的功能,并且zsh也支持它,因此我不称其为bashism
斯特凡Chazelas

6
@StephaneChazelas:你说的很对。我只是想指出POSIX标准不支持该语法,因此不能在/bin/sh脚本中普遍使用(许多人错误地在/bin/sh脚本中使用bash语法)。
理查德·汉森

对我来说有/dev/fd/62: Operation not supported什么线索吗?
2015年

1
有没有一种方法可以不将stderr重定向到日志文件?如果原始脚本是myscript我运行的./myscript > /dev/null,我应该仍然看到bye它的来源echo bye >&2
马丁·詹邦

0

将stderr和stdout写入文件,在屏幕上显示stderr(在stdout上)

exec 2> >(tee -a -i "$HOME/somefile.log")
exec >> "$HOME/somefile.log"

对克朗有用,因此您可以通过邮件收到错误(并且只有错误)

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.