Process Substitution---Bash进程替换使用教程

故事起源一次不太愉快的运维面试:

1
2
3
4
5
6
7
8
Me: 一个巨型日志文件,如何一次性统计总行数,包含关键字error和warning的行数?
He: cat log | wc -l; cat log | grep error | wc-l; cat log | grep warning | wc -l
Me: .... , 这不算一次性啊,提示下,tee
He: .... , tee 只支持文件啊...
Me: cat log | tee >(wc -l) >(grep error| wc -l | awk '{printf "error is %s\n",$1}' ) >(grep warning | wc -l awk '{printf "warning is %s\n",$1}') | tee
He: cat log | tee >(...) >(...) 是什么诡异语法?
Me: 传说中的Process substitution啊,blablabla
He: ....

He同学吐槽了我司的奇葩需求后,拂袖而去。当然,主因是我司无法担负期望薪资…

那么,大才He同学不是很明白的诡异语法到底是啥?这里开贴解释一二。

吐槽一下,虽然各路大才都对 *nix下的万物皆文件的理念表示激赏。但真摸清楚文件/文件描述/管道/等基本概念的,还真没几个……

Process Substitution的详细解释,参看 wikimedia 。实际上,认真看完并深入理解后,就可以直接关闭本页。

当然,对这个都没啥很正规中文翻译的feature希望有个快速理解和人话白话理解的话,请继续阅读。

Process Substitution

** Process Substitution ==

  • Bash和zsh的feature。是shell级别的,不是某条命令自己的功能。
  • ()中的执行体转变为文件
  • <()是执行体的输出
  • >()是执行体的输入
  • =()基本等同<()。但是,这个原理是生成temp文件。btw,这是zsh独有的。bash党可以无视。

被一堆list_item暴击后,应该有了初步理解了。这里,我们来看看刚才的例子的简写:

1
cat log | tee >(..a..) >(..b..)

tee,把输入的内容扔到一堆参数里面的指定的FILE中,顺手也原封不动的扔到 stdout打印到屏幕上。

1
tail -f running_log | tee log /var/backup/log.bak

这是tee的常规应用。(把日志保存到不同地点并且打印在屏幕上给苦逼运维看)

那么,我们例子里面的 a 和 b 是两个不同命令的执行体。在例子中,通过>()语法的加持,就变成了一个等待输入的文件。所以,tee的输出,光荣的变成了 a 和 b 的stdin,并被 a 和 b 分别执行起来。

嗯,就这么简单

是的,我懒了。遇到各种要价高的水货的郁闷也消散了。科普的心思也淡了。就写这里得了。

还是补充点。

1
2
$ echo >(ls)
/dev/fd/63

这能印证下吧。