2013-08-01 30 views
4

我想在管道输入上运行2个命令,并且想要打印(输出到stdout)两者的输出。每个命令都是grep,sed和awk的组合。Shell - 管道到文件中的多个命令

这两个命令都必须驻留在一个.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 

我尝试使用三通

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

更具可读性是它欺骗只用sed做呢? 'sed -n'h; s/World/Boy/g;/Boy/p; x;/World/p' pilcrow

回答

11

当你执行

tee >(some_command) 

庆典创建一个子shell来运行some_command。子壳的stdin被分配到管道的半个读数。 bash在命令行上留下了这个管道的名字,这样tee将把它的输入泵入管道。子外壳的stdoutstderr保持不变,所以它们仍然与tee相同。

所以,当你执行

tee >(some_command) | some_other_command 

现在,庆典首先创建一个进程运行tee,并赋予其stdout到书写一半的管道,而另一个进程来运行some_other_command,其stdin分配到相同管道的读数的一半。然后它创建另一个运行some_command的过程,如上所述,将其stdin分配给另一个管道的读数的一半,并保留其stdoutstderr不变。但是,stdout已被重定向到some_other_command,这就是some_command继承的内容。

在您的实际例子,

tee >(sed 's/World/Boy/g'|grep Boy) | grep World 

我们最终有:

    --> sed 's/World/Boy/g' --> grep Boy -- 
       /          \ 
input --> tee --<           \ 
       \           \ 
        ----------------------------------------------> grep World 

在在OP相连的一个问题,有一个(非接受,但正确的)答案F. Hauri,我在这里适应:

echo Hello World | 
((tee /dev/fd/5 | grep World >/dev/fd/4) \ 
      5>&1 | sed 's/World/Boy/' | grep Boy) 4>&1 

这需要一些练习阅读样T bash化他在上面。的重要部分是

(commands) 5>&1 

创建一个子外壳(())和给出了子外壳的FD编号为5,最初从stdout5>&1)复制。在子shell中,/dev/fd/5指的是fd。在子shell中,可以重定向stdout,但在stdout被复制到fd5后会发生这种情况。

+0

所以它应该正确吗? – SANDeveloper

+0

aaah。等待它。任何解决方案 – SANDeveloper

+0

@SANDeveloper:从一个答案,你在OP – rici

1

您可以使用pee(1) - 存在于Debian/Ubuntu的它在封装moreutils可用。

用途为你的榜样,一定程度上比魔术重定向

echo Hello World | pee 'grep World' 'sed "s/World/Boy/" | grep Boy'