将 stdout 和 stderr 通过管道传输到 shell 脚本中的两个不同进程?
我有一个管道正在这样做
command1 | command2
,所以, command1 的 stdout 转到 command2 ,而 command1 的 stderr 转到终端(或 shell 的 stdout 所在的任何地方)。
如何将 command1 的 stderr 传送到第三个进程 (command3
),同时 stdout 仍传送到 command2 ?
I've a pipline doing just
command1 | command2
So, stdout of command1 goes to command2 , while stderr of command1 go to the terminal (or wherever stdout of the shell is).
How can I pipe stderr of command1 to a third process (command3
) while stdout is still going to command2 ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
使用另一个文件描述符
您最多可以使用 7 个其他文件描述符:从 3 到 9。
如果您需要更多解释,请询问,我可以解释;-)
测试
输出:
示例
生成两个日志文件:
1. 仅
stderr
2.
stderr
和stdout
如果
command
是echo "stdout"; echo "stderr" >&2
然后我们可以这样测试它:Use another file descriptor
You can use up to 7 other file descriptors: from 3 to 9.
If you want more explanation, please ask, I can explain ;-)
Test
output:
Example
Produce two log files:
1.
stderr
only2.
stderr
andstdout
If
command
isecho "stdout"; echo "stderr" >&2
then we can test it like that:接受的答案会导致
stdout
和stderr
颠倒。这里有一个保留它们的方法(因为谷歌搜索这个目的会带来这篇文章):注意:
3>&-
来防止 fd 3 被 < 继承代码>命令。 (因为这可能会导致意外结果,具体取决于command
在内部执行的操作。)部分解释:
首先是外部部分:
3>&1
--{ ... }
的 fd 3 设置为 fd 1 em> 是(即stdout
)1>&2
--{ ... }
的 fd 1 设置为 fd 2 em> 是(即stderr
)stdout
)通过stdout_command
传送内部部分从外部部分继承文件描述符:
2>&1
--command
的 fd 2 设置为 fd 1 的值 (即stderr
根据外部部分)1>&3
--command
的 fd 1 设置为 fd 3 的值 (即stdout
根据外部部分)3>&-
--command
的 fd 3 设置为空(即关闭)stderr
)通过stderr_command
传送示例:
输出:(
a 的顺序 - > c
和b -> d
始终是不确定的,因为stderr_command
和stdout_command
。)The accepted answer results in the reversing of
stdout
andstderr
. Here's a method that preserves them (since Googling on that purpose brings up this post):Notice:
3>&-
is required to prevent fd 3 from being inherited bycommand
. (As this can lead to unexpected results depending on whatcommand
does inside.)Parts explained:
Outer part first:
3>&1
-- fd 3 for{ ... }
is set to what fd 1 was (i.e.stdout
)1>&2
-- fd 1 for{ ... }
is set to what fd 2 was (i.e.stderr
)| stdout_command
-- fd 1 (wasstdout
) is piped throughstdout_command
Inner part inherits file descriptors from the outer part:
2>&1
-- fd 2 forcommand
is set to what fd 1 was (i.e.stderr
as per outer part)1>&3
-- fd 1 forcommand
is set to what fd 3 was (i.e.stdout
as per outer part)3>&-
-- fd 3 forcommand
is set to nothing (i.e. closed)| stderr_command
-- fd 1 (wasstderr
) is piped throughstderr_command
Example:
Output:
(Order of
a -> c
andb -> d
will always be indeterminate because there's no form of synchronization betweenstderr_command
andstdout_command
.)使用进程替换:
请参阅 http://tldp.org/LDP/abs/html/ process-sub.html 了解更多信息。
Using process substitution:
See http://tldp.org/LDP/abs/html/process-sub.html for more info.
只需将 stderr 重定向到 stdout
注意:
commnd3
还将读取command2
stdout(如果有)。为了避免这种情况,您可以丢弃
commnd2
stdout:但是,要保留
command2
stdout(例如在终端中),那么请参考我另一个更复杂的答案。
测试
输出:
Simply redirect stderr to stdout
Caution:
commnd3
will also readcommand2
stdout (if any).To avoid that, you can discard
commnd2
stdout:However, to keep
command2
stdout (e.g. in the terminal),then please refer to my other answer more complex.
Test
output:
Zsh 版本
我喜欢 @antak 发布的答案,但由于多操作系统,它在 zsh 中无法正常工作。以下是在 zsh 中使用它的一个小调整:
要使用它,请将
command
替换为您要运行的命令,并替换stderr_command
和stdout_command
与您想要的管道。例如,命令ls / /foo
将产生stdout输出和stderr输出,因此我们可以将其用作测试用例。要将 stdout 保存到名为 stdout 的文件,将 stderr 保存到名为 stderr 的文件,可以执行以下操作:请参阅 @antak 的原始答案以获取完整说明。
Zsh Version
I like the answer posted by @antak, but it doesn't work correctly in zsh due to multios. Here is a small tweak to use it in zsh:
To use, replace
command
with the command you want to run, and replacestderr_command
andstdout_command
with your desired pipelines. For example, the commandls / /foo
will produce both stdout output and stderr output, so we can use it as a test case. To save the stdout to a file called stdout and the stderr to a file called stderr, you can do this:See @antak's original answer for full explanation.
照常管道 stdout,但使用 Bash 进程替换来进行 stderr 重定向:
标头:
#!/bin/bash
Pipe stdout as usual, but use Bash process substitution for the stderr redirection:
Header:
#!/bin/bash
使用 fifo 可以相当容易地实现相同的效果。我不知道执行此操作的直接管道语法(尽管看到一个会很漂亮)。这就是使用 fifo 的方法。
首先,打印到
stdout
和stderr
,outerr.sh
:然后我们可以这样做:
这样你就可以设置首先监听
stderr
输出,并且它会阻塞,直到它有一个编写器,这发生在下一个命令中,使用语法2>err
。您可以看到每个wc -c
都有 20 个输入字符。如果您不想让 fifo 继续存在(即
rm
),请不要忘记在完成后清理 fifo。如果另一个命令需要在stdin
上输入而不是文件参数,您可以使用输入重定向,例如wc -c
wc -c
wc -c
wc -c
wc -c
也犯错误。
The same effect can be accomplished fairly easily with a fifo. I'm not aware of a direct piping syntax for doing it (though it would be nifty to see one). This is how you might do it with a fifo.
First, something that prints to both
stdout
andstderr
,outerr.sh
:Then we can do something like this:
That way you set up the listener for
stderr
output first and it blocks until it has a writer, which happens in the next command, using the syntax2>err
. You can see that eachwc -c
got 20 characters of input.Don't forget to clean up the fifo after you're done if you don't want it to hang around (i.e.
rm
). If the other command wants input onstdin
and not a file arg, you can use input redirection likewc -c < err
too.已经过去很长一段时间了,但是...
@oHo 的答案有一个缺点,即将
command2
输出重定向到stderr
。虽然@antak的答案可能会颠倒输出的顺序。下面的解决方案可能会通过将
command2
和command3
输出和错误分别正确重定向到stdout
和stderr< 来解决这些问题/code>,如预期并保持顺序。
当然,它也满足了OP将输出和错误从
command1
分别重定向到command2
和command3
的需要。It's been a long time but...
@oHo's answer has the disadvantage of redirecting
command2
outputs tostderr
. While @antak's answer may reverse the order of the outputs.The solution below is likely to fix these problems by correctly redirecting
command2
andcommand3
outputs and errors to, respectively,stdout
andstderr
, as expected and preserving order.Of course, it also satisfies the OP's need to redirect output and errors from
command1
to, respectively,command2
andcommand3
.