我想在管道输入上运行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,但是我不知道如何在脚本中使用命名管道。

最佳答案

执行时

tee >(some_command)

bash创建一个子 shell 来运行some_command。子 shell 的stdin分配给管道的读取部分。 bash在命令行上保留该管道的名称,以便tee将其输入泵入管道。子 shell 的stdoutstderr保持不变,因此它们仍然与tee相同。

所以,当你执行
tee >(some_command) | some_other_command

现在,bash首先创建一个运行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

阅读上面的bashisms需要一些练习。重要的是
( commands ) 5>&1

创建一个子shell(( ))并为该子shell提供一个编号为5的fd,该文件最初是从stdout(5>&1)复制而来的。在子 shell 中,/dev/fd/5引用该fd。在子 shell 中,可以重定向stdout,但这将在将stdout复制到fd5之后发生。

关于bash - Shell-管道传输到文件中的多个命令,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17983777/

10-16 20:54