我想在管道输入上运行2个命令,并希望打印(到stdout)两者的输出。
每个命令都是grep,sed和awk的组合。
这两个命令都必须位于单个.sh文件中。
示例命令:
cat mult_comm.sh
sed 's/World/Boy/g'|grep Boy ; grep World
# Input
cat input.log
Hello World
# This command HAS to work EXACTLY like this
cat input.log | bash mult_comm.sh
预期输出
Hello Boy
Hello World
实际输出
Hello Boy
我尝试使用tee
cat mult_comm.sh
tee >(sed 's/World/Boy/g'|grep Boy) | grep World
但这只给出了
Hello World
我可以根据需要修改.sh文件,但无法更改管道命令。有什么想法吗?
这类似于OS X / Linux: pipe into two processes?和Pipe output to two different commands,但我无法弄清楚如何在脚本中使用命名管道。
答案 0 :(得分:13)
执行时
tee >(some_command)
bash创建一个子shell来运行some_command
。子shell的stdin
被分配给管道的读数的一半。 bash在命令行中保留此管道的名称,以便tee
将其输入泵入管道。子shell的stdout
和stderr
保持不变,因此它们仍然与tee
相同。
所以,当你执行
时tee >(some_command) | some_other_command
现在,bash首先创建一个运行tee
的进程,并将其stdout
分配给管道的写入一半,另一个进程运行some_other_command
,其{{1}分配给同一管道的读数的一半。然后,它创建另一个运行stdin
的流程,如上所述,将其some_command
分配给另一个管道的读取一半,并保持其stdin
和stdout
不变。但是,stderr
已经重定向到stdout
,这就是some_other_command
继承的内容。
在您的实际示例中,
some_command
我们最终得到:
tee >(sed 's/World/Boy/g'|grep Boy) | grep World
在OP中关联的一个问题中,F. Hauri有一个(未接受但正确的)答案,我在此处进行了调整:
--> sed 's/World/Boy/g' --> grep Boy --
/ \
input --> tee --< \
\ \
----------------------------------------------> grep World
像上面这样阅读bashisms需要一些练习。重要的是
echo Hello World |
((tee /dev/fd/5 | grep World >/dev/fd/4) \
5>&1 | sed 's/World/Boy/' | grep Boy) 4>&1
创建一个子shell(( commands ) 5>&1
)并为该子shell提供一个编号为5的fd,最初从( )
(stdout
)复制。在子shell中,5>&1
指的是fd。在子shell中,可以重定向/dev/fd/5
,但是在将stdout复制到fd5之后会发生这种情况。
答案 1 :(得分:1)
您可以使用pee(1)
- 在Debian / Ubuntu中,它可以在moreutils
包中找到。
您的示例的用法,比魔术重定向更具可读性
echo Hello World | pee 'grep World' 'sed "s/World/Boy/" | grep Boy'