现在的位置: 首页 > 综合 > 正文

Bash中的进程替换(process substitution)

2013年08月01日 ⁄ 综合 ⁄ 共 1514字 ⁄ 字号 评论关闭

进程替换(process substitution)是Bash中的一个有意思的语法。

              语法规则:使用 <()  or  >()    <>与(之间没有空格

很多有关Bash的文档对这条规则并没有解释得很清楚,在这里综合部分搜索后的结果,得出个人理解:

首先举一个例子,看一下进程替换做了什么 :

a>    cat  <(ls)                #输出了当前目录下所有文件和目录的名称

b>    echo <(ls)             #输出/dev/fd/63

左边是比较简单的命令,cat 输出文件内容以文件的名称为参数,echo显示作为参数的字符文本。右边是使用相同的进程替换的部分<(ls),先不管<()和>()到底表示什么意思,根据执行结果的不同,容易观察并得出结论 <(ls)生成了一个名为/dev/fd/63的部分,它到底是什么?个人理解是共享文件但不是命名管道的概念,虽然/dev/fd/0 ,/dev/fd/1,/dev/fd/2有自己特定的含义。所以cat才能以文件读取它的内容并显示出来。这里需要说明的是<(ls)已经改变了ls的输出定向。因为如果此时ls的标准输出还是stdout的话,那么终端上应该是显示同样的内容两次,实际上只有一次。后面会提到,这跟>()是不同的。

注意前面提到了shell命令的参数,<() 给其它命令提供了参数。为什么这么做,难道Bash中已有重定向和管道还不够吗?广大屌丝朋友们我们在终端敲命令的时候,或者在脚本中,有的时候真的不想把命令敲太死,想有点变化,或者有什么东西除了变量扩展命令替换还能替换命令的参数。

既然<()能产生/dev/fd/63这样的文件名称,自然也能运用到重定向

         while read lines ; do echo $lines ;done < <(ls)

>()是很让人误解的语法规则,GNU-Bash的文档解释说>()为()中的命令提供输入,一开始以为就是管道的概念,但两者其实是不同的。因为如果>()能改变它左边命令的输出定向的话,那么下面的命令行应该只会显示一次文本内容,反之如何

          ps  | tee >(cat)         #同样的内容在终端上重复显示

出了什么问题呢?正如GNU-Bash文档说明的那样,<() >()类似于命令替换和变量扩展,个人猜测Bash在解释这样的命令时,首先就是创建这个“共享文件”/dev/fd/63,然后将这个文件名传给>() 左边的命令tee作为tee的参数(用来输出的文件名),然后传给右边()中的命令作为其输入命令的参数,这样实现了类似管道的功能。根据上面的例子,再举一例就彻底明白所谓的进程替换是什么概念了:

           $ ps | tee > >(grep bash)           #改变tee的输出定向,这里使用grep是为了确定终端的显示是由哪个命令产生的,内容输出没有重复

要满足>()语法规则的命令实际上并不多如:

          $ tee
>
(wc -l>&2)< bigfile|gzip>
bigfile.gz

请参考

http://en.wikipedia.org/wiki/Process_substitution 

http://blog.sanctum.geek.nz/bash-process-substitution/ 

http://wiki.bash-hackers.org/syntax/expansion/proc_subst

高级Bash脚本编程指南  杨春敏 黄毅   

http://wiki.bash-hackers.org/howto/redirection_tutorial

抱歉!评论已关闭.