如何通过管道传输 stderr 而不通过管道传输 stdout

如何通过管道传输 stderr 而不通过管道传输 stdout

如何在不通过管道传输标准输出流的情况下通过管道传输标准错误流?

我知道这个命令有效,但是它也会写出标准。

Command 2>&1 | tee -a $LOG

我怎样才能得到标准错误?

注意:我想要的是将 stderr 流写入日志并将 stderr 和 stdout 写入控制台。

答案1

为此,使用一个额外的文件描述符来切换 stderr 和 stdout:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

基本上,它是有效的,或者至少我认为它是有效的,如下所示:
重定向是从左到右进行评估的。

3>&1创建一个新的文件描述符 3,作为 fd 1 (stdout) 的重复项(副本)。

1>&2使 stdout (1) 成为 fd 2 (stderr) 的副本

2>&3制作 fd 2,即 3 的重复(副本),而 3 之前是 stdout 的副本。

因此现在 stderr 和 stdout 已切换。

| tee foo.filetee 重复了文件描述符 1,并将其放入 stderr。

答案2

Kyle 的 Unix/Linux 命令负责将 STDERR 与 STDOUT 进行切换;但是解释并不完全正确。重定向操作符不执行任何复制或重复,它们只是将流重定向到不同的方向。

通过暂时将 3>&1 移至末尾来重写 Kyle 的命令,将使我们更容易理解这个概念:

find /var/log  1>&2  2>&3  3>&1  

但是,如果这样写,Linux 会显示错误,因为 &3 还不存在,因为它位于 3>&1 之前。3>something 是一种声明(定义)我们将使用第三根管道的方式,因此必须在我们将水流入该管道之前找到它,例如 Kyle 写的方式。试试这个其他方法,只是为了好玩:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

没有办法进行复制真是可惜。您无法在同一个命令中执行“3>&1 3>&2”之类的操作,因为 Linux 只会使用找到的第一个,而忽略第二个。

我还没有找到一种方法,用一个命令将错误和常规输出发送到一个文件,并将错误的副本发送到标准输出。例如,我有一个 cron 作业,我希望两个输出(错误和标准)都转到一个日志文件,并让错误也发出去,以电子邮件的形式发送到我的黑莓手机。我可以用两个命令使用“tee”来做到这一点,但错误在文件中的常规输出行中没有按正确的顺序显示。这是我解决问题的糟糕方法:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

请注意,我必须使用 log1 两次,并且必须在两种情况下附加,第一次使用“tee”命令的“-a”选项,第二次使用“>>”。

做一个猫日志1您将获得以下内容:

STD1
STD2
-bash: sdfr: command not found

请注意,错误并未像应该的那样显示在第二行。

答案3

根据 ksh(pdksh)的手册页,您可以执行以下操作:

命令 2>&1 >/dev/null | cat -n

即复制 stderr 到 stdout,将 stdout 重定向到 /dev/null,然后通过管道传输到‘cat -n’

在我的系统上,pdksh 可以运行:

$ errorecho(){ echo "$@" >&2;}

$ errorecho foo

$ errorecho foo >/dev/null # 即使 stdout 重定向,仍应显示

$ errorecho foo 2>&1>/dev/null | cat -n
     一 foo
$   

答案4

我让它像你想要的那样运行,因为我也需要它并改进了你的命令。现在对我来说,它在 debian squeeze 上使用 bash 3.2 可以正常工作

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

而 log1 记录 stdout 和 stderr,而 log2 仅记录 stderr,不记录任何其他内容到屏幕上。

相关内容