Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 在shell脚本中将stdout和stderr管道传输到两个不同的进程?_Bash_Shell_Pipe_Io Redirection - Fatal编程技术网

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(was
    stdout
    )通过
    stdout_命令
  • 内部零件从外部零件继承文件描述符:

  • 2>&1
    --
    命令
    的fd 2设置为fd 1的值(即根据外部零件设置的
    stderr
  • 1>&3
    --
    命令
    的fd 1设置为fd 3原来的值(即根据外部零件设置的
    stdout
  • 3>&-
    --
    命令
    的fd 3设置为无(即关闭)
  • | stderr_命令
    ——fd 1(was
    stderr
    )通过
    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