使用bash,如何将标准错误输出到另一个进程中?

172

我们都知道如何将一个进程的标准输出导入另一个进程的标准输入:

proc1 | proc2

但是如果我想将proc1的标准错误发送到proc2,同时保留标准输出流到当前位置怎么办?你可能会认为有一个类似以下命令的指令:

proc1 2| proc2

但是,唉,没有。有什么办法可以做到这一点吗?

你可以在rc中进行这样简单的重定向,它是另一个shell。例如:proc1 |[2] proc2。很不错吧? 但在bash中不行。 - Rolf
相关:如何在bash中同时重定向stdout和stderr?。并且这里有一个最简单的答案来同时重定向stdout和stderr。 - Gabriel Staples
5个回答

214

还有进程替换的方法,可以将进程替换为文件。
您可以按如下方式将stderr发送到文件:

process1 2> file

但是你可以按照以下步骤,用进程替代文件:

process1 2> >(process2)

这里有一个具体的例子,将stderr发送到屏幕并追加到日志文件中。

sh myscript 2> >(tee -a errlog)

1
我尝试了这个命令(weston --help 2> >(less)),但它没有起作用,反而破坏了我的shell,我不得不退出并重新登录。 - Rolf
2
@Rolf 如果 weston --helpless 都期望有键盘交互,但只有其中一个接收到了输入,那么你可能会陷入尴尬的境地。尝试使用类似 grep 的东西进行测试。此外,你可能会发现鼠标/键盘输入都被发送到第二个命令,而不是 weston。 - BeowulfNode42
3
如果您想要重定向stderr和stdout,请使用“|&”,我从这里学到了它。 - ᐅdevrimbaris

105
您可以使用以下技巧来交换stdoutstderr。然后您只需使用常规的管道功能。
( proc1 3>&1 1>&2- 2>&3- ) | proc2

如果在开始时提供的stdoutstderr都指向同一个位置,那么这将为您提供所需的结果。

x>&y的作用是更改文件句柄x,使其现在将数据发送到文件句柄y当前所指向的位置。对于我们的特定情况:

  • 3>&1创建一个新的句柄3,它将输出到当前的句柄1(原始的stdout),只是为了将其保存在下面的最后一条记录中。
  • 1>&2修改句柄1(stdout)以输出到当前的句柄2(原始的stderr)。
  • 2>&3-修改句柄2(stderr)以输出到当前的句柄3(原始的stdout),然后通过结尾处的-关闭句柄3

它实际上就像你在排序算法中看到的交换命令一样:

temp   = value1;
value1 = value2;
value2 = temp;

5
在这里使用1>&2-相比于仅使用1>&2的价值是什么?如果我们只是立即重新打开/重新分配它,我不理解为什么要关闭fd 2 - dubiousjim
2
@dubiousjim,在那种特定情况下没有优势,我猜我这样做只是为了保持一致 - 关闭文件句柄3是一个很好的主意,以释放它。 - paxdiablo
尝试让gcc的make(在我的系统上已经着色)与此命令一起工作:“(make 3>&1 1>&2- 2>&3-)| less -R”,而“(ls -al 3>&1 1>&2- 2>&3-)| less -R”则按预期工作。 - unsynchronized
@aghsmith,情况并非如此,左侧的句柄始终是被设置的,右侧的东西用于设置它(无论是句柄还是文件名)。 - paxdiablo
@aghsmith:好的,让我看看能不能稍微整理一下。 - paxdiablo
显示剩余2条评论

89

Bash 4有这个功能:

如果使用 `|&',则通过管道将command1的标准错误连接到command2的标准输入;它是2>&1 |的简写。此标准错误的隐式重定向在命令指定的任何重定向之后执行。

zsh也具有此功能。

--

在其他/旧的shell中,只需明确输入以下内容:

FirstCommand 2>&1 | OtherCommand


17
从阅读文档来看,它不仅输出标准错误信息,还输出正常的内容,这很好知道。我想是时候开始研究Bash 4了。 - paxdiablo
当前的Bash手册中写道:“如果使用|&,则命令的标准错误输出除了其标准输出之外,还会连接到command2的标准输入”。这明确不是OP想要的。 - Peter - Reinstate Monica
@PeterA.Schneider:OP说“让标准输出保持在当前位置”,这可能是含糊不清的。 - Dennis Williamson
我没有看到任何歧义。你的建议 (1) 混淆了这两个流。 (2) OtherCommand 在某个地方写入 合并后 的数据,可能是其他地方。因此,它不是相同的数据,并且可能被传输到其他地方。这与 OP 的期望正好相反,对吗? - Peter - Reinstate Monica
@PeterA.Schneider:标准输出的当前位置在哪里?如果proc1输出到stdout和stderr,并且您希望将stderr发送到proc2的stdin(这是proc1的stdout所在的位置),那么我的答案就可以实现。我给了OP他所“要求”的,也许不是他“想要”问的。其中存在潜在的歧义。OP接受了交换stdout和stderr的答案,这不是他要求的。 - Dennis Williamson
显示剩余6条评论

34

交换是很好的,因为它解决了问题。如果您甚至不需要原始的标准输出,您可以这样做:

proc1 2>&1 1>/dev/null | proc2

顺序非常重要;你不希望:

proc1 >/dev/null 2>&1 | proc1

由于这将把所有内容都重定向到 /dev/null


4

这些方法都不是很有效。我找到的最好的方法是:

(command < input > output) 2>&1 | less

这仅适用于command不需要键盘输入的情况,例如:

(gzip -d < file.gz > file) 2>&1 | less

将gzip错误放入less中


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接