Bash 在shell脚本中将stdout和stderr管道传输到两个不同的进程?
我有一条管线正在做Bash 在shell脚本中将stdout和stderr管道传输到两个不同的进程?,bash,shell,pipe,io-redirection,Bash,Shell,Pipe,Io Redirection,我有一条管线正在做 command1 | command2 因此,command1的stdout转到command2,而command1的stderr转到终端(或者shell的stdout所在的任何地方) 当stdout仍将运行到command2时,如何将command1的stderr传输到第三个进程(command3)呢?使用fifo可以相当轻松地实现相同的效果。我不知道使用直接管道语法来做这件事(尽管看到它会很好)。这就是使用fifo的方式 首先,打印到stdout和stderr,out
command1 | command2
因此,command1的stdout转到command2,而command1的stderr转到终端(或者shell的stdout所在的任何地方)
当stdout仍将运行到command2时,如何将command1的stderr传输到第三个进程(
command3
)呢?使用fifo可以相当轻松地实现相同的效果。我不知道使用直接管道语法来做这件事(尽管看到它会很好)。这就是使用fifo的方式
首先,打印到stdout
和stderr
,outerr.sh
:
#!/bin/bash
echo "This goes to stdout"
echo "This goes to stderr" >&2
然后我们可以这样做:
$ mkfifo err
$ wc -c err &
[1] 2546
$ ./outerr.sh 2>err | wc -c
20
20 err
[1]+ Done wc -c err
这样,您可以首先为stderr
输出设置侦听器,然后使用语法2>err
将其阻塞,直到它有一个writer,这在下一个命令中发生。您可以看到每个wc-c
都有20个字符的输入
如果不想让fifo挂起(即rm
),请不要忘记在完成后清理fifo。如果另一个命令需要在stdin
上输入,而不是文件arg,则也可以使用类似wc-c
的输入重定向。使用另一个文件描述符
您最多可以使用7个其他文件描述符:从3到9。如果您需要更多解释,请询问,我可以解释;-) 试验 输出:
b2
a1
a2
b2
c2
----12
例子
生成两个日志文件:1. <代码>标准代码仅限
2. <代码>标准码和标准码
{ { { command 2>&1 1>&3; } | tee err-only.log; } 3>&1; } > err-and-stdout.log
如果命令
为回显“stdout”;echo“stderr”>&2
然后我们可以这样测试它:
$ { { { echo out>&3;echo err>&1;}| tee err-only.log;} 3>&1;} > err-and-stdout.log
$ head err-only.log err-and-stdout.log
==> err-only.log <==
err
==> err-and-stdout.log <==
out
err
${{echo out>&3;echo err>&1;}| tee err only.log;}3>&1;}>err-and-stdout.log
$head err-only.log err-and-stdout.log
==>err-only.log err-and-stdout.log只需将stderr重定向到stdout即可
注意:commnd3
也将读取command2
stdout(如果有)。
为了避免这种情况,您可以放弃commnd2
stdout:
{ command1 | command2 >/dev/null; } 2>&1 | command3
但是,要保留command2
stdout(例如在终端中),
那么请参考我的另一个更复杂的答案
试验
输出:
b2
a1
a2
b2
c2
----12
接受的答案会导致stdout
和stderr
的反转。这里有一个保存它们的方法(因为谷歌搜索了这个帖子):
注意:
3>&-
是防止fd 3被命令继承所必需的。(这可能会导致意外结果,具体取决于命令的内部功能。)
解释部分:
第一部分:
3>&1
--{…}
的fd 3设置为fd 1的值(即stdout
)
1>&2
--{…}
的fd 1设置为fd 2的值(即stderr
)
| stdout_命令
——fd 1(wasstdout
)通过stdout_命令
内部零件从外部零件继承文件描述符:
2>&1
--命令
的fd 2设置为fd 1的值(即根据外部零件设置的stderr
)
1>&3
--命令
的fd 1设置为fd 3原来的值(即根据外部零件设置的stdout
)
3>&-
--命令
的fd 3设置为无(即关闭)
| stderr_命令
——fd 1(wasstderr
)通过stderr_命令
例子:
输出:
(由于stderr\u命令
和stdout\u命令
之间没有同步形式,a->c
和b->d
的顺序始终是不确定的)使用进程替换:
command1 > >(command2) 2> >(command3)
有关更多信息,请参阅。像往常一样使用管道标准输出,但使用Bash进程替换标准输出重定向:
some_command 2> >(command of stderr) | command of stdout
标题:#/bin/bash
Zsh版本
我喜欢@antak发布的,但由于多操作系统,它在zsh中无法正常工作。下面是在zsh中使用它的一个小调整:
{ unsetopt multios; command 2>&1 1>&3 3>&- | stderr_command; } 3>&1 1>&2 | stdout_command
要使用,请将命令
替换为要运行的命令,并将stderr_命令
和stdout_命令
替换为所需的管道。例如,命令ls//foo
将生成stdout输出和stderr输出,因此我们可以将其用作测试用例。要将stdout保存到名为stdout的文件中,将stderr保存到名为stderr的文件中,可以执行以下操作:
{ unsetopt multios; ls / /foo 2>&1 1>&3 3>&- | cat >stderr; } 3>&1 1>&2 | cat >stdout
请参阅@antak的原始答案以获得完整解释。哇,好电话。我最初认为OP希望stderr只转到命令3
。这看起来是正确的方法。难道不是{command1 | command2>/dev/null 2>&1}2>&1 | command3
阻止command2的stdout/stderr到达command3,或者这也会干扰command1的stderr吗?Hi@user964970。/dev/null
重定向是个好主意。正如您所说,上面的示例混乱了stderr
和stdout
,因为它们在同一步骤中被颠倒了。我更喜欢{command1 | command2>/dev/null;}2>&1 | command3
。我编辑我的答案是为了利用你的杰出贡献。谢谢;-)这个答案的一个问题是{}创建了一个子shell,在某些情况下是不可接受的。例如,您不能将变量从{}中传回。看起来OP希望stdout
和stderr
都转到command2
,而我最初错过了它。上面将两者分开,并分别发送给命令。不过我会留下它,因为它可能对某些人有用。不,我不希望stdout和stderr都转到command2。命令1到命令2的标准输出,命令1到命令3的标准输出。command2不应获取Command1的stderr如何添加文件描述符<代码>回声输出>&3
输出“-bash:3:Bad file descriptor”在这里找到了答案:下面安塔克的答案更完整。它仍然保持标准输出和标准输出之间的原始分离
out: a
err: b
err: d
out: c
command1 > >(command2) 2> >(command3)
some_command 2> >(command of stderr) | command of stdout
{ unsetopt multios; command 2>&1 1>&3 3>&- | stderr_command; } 3>&1 1>&2 | stdout_command
{ unsetopt multios; ls / /foo 2>&1 1>&3 3>&- | cat >stderr; } 3>&1 1>&2 | cat >stdout