我想做一些与此相同的事情:
some-expensive-command > /tmp/mytempfile
grep -v "pattern" /tmp/mytempfile >> output.txt
grep "pattern" /tmp/mytempfile | yet-another-command
最好是优雅的,不需要tempfile
。我考虑过通过管道tee
,但我能想到的最好的办法可能是将三条线中的两条结合起来,仍然需要中间存储:
some-expensive-command | tee /tmp/mytempfile | grep -v "pattern" >> output.txt
grep "pattern" /tmp/mytempfile | yet-another-command
答案1
问题读起来听起来你想要一个 stdin 重定向到两个不同的命令如果是这种情况,请利用tee
加法过程替换:
some-expensive-command | tee >(grep 'pattern' > output.txt) >(grep -v 'pattern' | another-command)
进程替换实际上是在 bash 内部实现的匿名管道(在子进程级别)。我们还可以使用命名管道 + tee
。例如,在终端 A 中执行
$ mkfifo named.fifo
$ cat /etc/passwd | tee named.fifo | grep 'root'
在另一个终端 B 上执行
$ grep -v 'root' named.fifo
另一种看待这个问题的方式是认识grep
到线模式匹配工具,因此通过一次读取行并在多个命令中使用同一行,我们可以实现完全相同的效果:
rm output.txt # get rid of file so that we don't add old and new output
some-expensive-command | while IFS= read -r line || [ -n "$line" ]; do
printf "%s\n" "$line" | grep 'pattern' >> output.txt
printf "%s\n" "$line" | grep -v 'pattern' | another-command
done
# or if another-command needs all of the output,
# place `| another-comand` after `done` clause
另一种方法是放弃grep
并使用更强大的方法,例如awk
:
some-expensive-command | awk '/pattern/{print >> "output.txt"}; !/pattern/{print}' | another-command.
实际上,不用担心使用临时文件,只要在使用后清理它们即可。如果有效,那就有效。
答案2
使用bash
流程替代:
some-command | tee >(grep "pat" | another-command >>out1) | grep -v "pat" >>out2
进程替换将some-command
的输出分配给grep "pat"
的输入,从而为您节省了临时文件。当然,数据仍然保存在文件中(总是如此),只是您不必关心这一点。如果您不想将another-command
的输出保存在文件中,而是打印它,我建议只需切换两个命令列表。
另一个很好的信息来源:man bash
/扩张