给出运行“ foo” 的命令,以便将其输出传递到程序“ pout” 中,并将其错误传递到程序“ perr “ , 并且“ pout” 的所有输出都在stdout上,而“ perr” 的所有输出都在标准错误上。使用文件流复制。不要使用命名管道。
我无法弄清楚流复制的工作原理,因此我尝试使用普通管道进行复制。一些有助于理解流复制的技术将非常有用。
( ./foo | ./pout ) 2>&1 | ./perr
答案 0 :(得分:2)
您应该看看https://wiki.bash-hackers.org/howto/redirection_tutorial。让我们看看这如何适用于您的示例:
让我们提供一些shell函数来进行尝试:
# Some helper to show you what is is going on with the file descriptors:
function lofd { lsof -ad 0,1,2,3,4 -p $BASHPID -w; }
# foo's stdout goes into pout, foo's stderr goes to perr:
function foo { echo foo-out; echo foo-err 1>&2; lofd; }
function pout { sed 's/foo-out/pout-out/'; echo pout-err 1>&2; lofd; }
function perr { sed 's/foo-err/perr-out/'; echo perr-err 1>&2; lofd; }
检查foo
到stderr
和stdout
的输出:
foo 1>out 2>err
grep "" out err
将foo
到pout
,同时将pout
打印到stderr
和stdout
:
{ foo | pout; } 1>out 2>err
grep "" out err
确保pout
的所有输出都流向stdout
:
{ foo | pout 2>&1; } 1>out 2>err
grep "" out err
现在,它变得棘手:当我们通过perr
通过管道传输(确保来自perr
的所有输出都流向stderr
)时,我们看到perr
从pout
和stderr
中的foo
通过:
{ { foo | pout 2>&1; } | perr 1>&2; } 1>out 2>err # not as intended
grep "" out err
我们只能在某些临时文件描述符的帮助下进行管理。一方面,我们将fd 3用作stdout
的备份。然后pout
可以使用它来将管道“旁路”到perr
中:
{ { { foo | pout 1>&3 2>&3; } | perr 1>&2; } 3>&1; } 1>out 2>err
grep "" out err
此外,我们使用fd 4将管道移交到perr
中,以便foo
可以使用它:
{ { { foo 2>&4 | pout 1>&3 2>&3; } 4>&1 | perr 1>&2; } 3>&1; } 1>out 2>err
grep "" out err
最后,进行一些清理(关闭未使用的文件描述符:查看lsof
的输出以了解此处的情况)
{ { { foo 2>&4 3>&- 4>&- | pout 1>&3 2>&3 3>&- 4>&-; } 4>&1 | perr 1>&2 3>&-; } 3>&1; } 1>out 2>err
grep "" out err
没有我们的调试上下文:
{ { foo 2>&4 3>&- 4>&- | pout 1>&3 2>&3 3>&- 4>&-; } 4>&1 | perr 1>&2 3>&-; } 3>&1
瞧!
答案 1 :(得分:1)
使用其他管道(此处为5)
( ( ./foo | ./pout ) 2>&1 1>&5 | ./perr ) 5>&1
2>&1
将stderr重定向到stdout 1>&5
将标准输出重定向到pipe5 ./perr
看不到./pout
的标准输出5>&1
再次将pipe5重定向到stdout。