In addition to the fairly common forms of input/output redirection the shell recognizes something called process substitution. Although not documented as a form of input/output redirection, its syntax and its effects are similar.
The syntax for process substitution is:
<(list) or >(list)where each list is a command or a pipeline of commands. The effect of process substitution is to make each list act like a file. This is done by giving the list a name in the file system and then substituting that name in the command line. The list is given a name either by connecting the list to named pipe or by using a file in /dev/fd (if supported by the O/S). By doing this, the command simply sees a file name and is unaware that its reading from or writing to a command pipeline.
To substitute a command pipeline for an input file the syntax is:
command ... <(list) ...To substitute a command pipeline for an output file the syntax is:
command ... >(list) ...
At first process substitution may seem rather pointless, for example you might imagine something simple like:
uniq <(sort a)to sort a file and then find the unique lines in it, but this is more commonly (and more conveniently) written as:
sort a | uniqThe power of process substitution comes when you have multiple command pipelines that you want to connect to a single command.
For example, given the two files:
# cat a e d c b a # cat b g f e d c bTo view the lines unique to each of these two unsorted files you might do something like this:
# sort a | uniq >tmp1 # sort b | uniq >tmp2 # comm -3 tmp1 tmp2 a f g # rm tmp1 tmp2With process substitution we can do all this with one line:
# comm -3 <(sort a | uniq) <(sort b | uniq) a f g
Depending on your shell settings you may get an error message similar to:
syntax error near unexpected token `('when you try to use process substitution, particularly if you try to use it within a shell script. Process substitution is not a POSIX compliant feature and so it may have to be enabled via:
set +o posixBe careful not to try something like:
if [[ $use_process_substitution -eq 1 ]]; then set +o posix comm -3 <(sort a | uniq) <(sort b | uniq) fiThe command set +o posix enables not only the execution of process substitution but the recognition of the syntax. So, in the example above the shell tries to parse the process substitution syntax before the "set" command is executed and therefore still sees the process substitution syntax as illegal.
Of course, note that all shells may not support process substitution, these examples will work with bash.
q程替换与命令替换很怼. 命o(h)替换把一个命令的l果赋值给一个变? 比如dir_contents=`ls -
al`或xref=$( grep word datafile). q程替换把一个进E的输出提供l另一个进E?换句话说, 它把
一个命令的l果发给?jin)另一个命?.
命o(h)替换的模?/p>
用圆括号扩v来的命o(h)
>(command)
<(command)
启动q程替换. 它?dev/fd/<n>文g圆括号中的q程处理l果发送给另一个进E? [1] (?/p>
者注: 实际上现代的UNIXcL作系l提供的/dev/fd/n文g是与文g描述W相关的, 整数n指的?/p>
是进E运行时对应数字的文件描q符)
?<"?>"与圆括号之间是没有空格的. 如果加了(jin)I格, ?x)生错?
bash$ echo >(true)
/dev/fd/63
bash$ echo <(true)
/dev/fd/63
Bash在两个文件描q符之间创徏?jin)一个管? --fIn和fOut--. true命o(h)的stdin被连接到fOut
(dup2(fOut, 0)), 然后Bash?dev/fd/fIn作ؓ(f)参数传给echo. 如果pȝ~Z/dev/fd/<n>文g, Bash?/p>
使用临时文g. (感谢, S.C.)
q程替换可以比较两个不同命o(h)的输? 甚至能够比较同一个命令不同选项情况下的输出.
bash$ comm <(ls -l) <(ls -al)
total 12
-rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0
-rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2
-rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh
total 20
drwxrwxrwx 2 bozo bozo 4096 Mar 10 18:10 .
drwx------ 72 bozo bozo 4096 Mar 10 17:58 ..
-rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0
-rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2
-rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh
使用q程替换来比较两个不同目录的内容(可以查看哪些文g名相? 哪些文g名不?:
1 diff <(ls $first_directory) <(ls $second_directory)
一些进E替换的其他用法与技?
1 cat <(ls -l)
2 # {h(hun)?ls -l | cat
3
4 sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin)
5 # 列出pȝ3个主?bin'目录中的所有文? q且按文件名q行排序.
6 # 注意??查一? 上面?个圆括号)明显不同的命令输Z递给'sort'.
7
8
9 diff <(command1) <(command2) # l出两个命o(h)输出的不同之?
10
11 tar cf >(bzip2 -c > file.tar.bz2) $directory_name
12 # 调用"tar cf /dev/fd/?? $directory_name", ?bzip2 -c > file.tar.bz2".
13 #
14 # 因ؓ(f)/dev/fd/<n>的系l属?
15 # 所以两个命令之间的道不必被命?
16 #
17 # q种效果可以被模拟出?
18 #
19 bzip2 -c < pipe > file.tar.bz2&
20 tar cf pipe $directory_name
21 rm pipe
22 # ?/p>
23 exec 3>&1
24 tar cf /dev/fd/4 $directory_name 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&-
25 exec 3>&-
26
27
28 # 感谢, Stephane Chazelas
一个读者给我发?jin)一个有的例子, 是关于进E替换的, 如下.
1 # 摘自SuSE发行版中的代码片?
2
3 while read des what mask iface; do
4 # q里省略?jin)一些命?..
5 done < <(route -n)
6
7
8 # Z(jin)试? 我们让它做点?
9 while read des what mask iface; do
10 echo $des $what $mask $iface
11 done < <(route -n)
12
13 # 输出:
14 # Kernel IP routing table
15 # Destination Gateway Genmask Flags Metric Ref Use Iface
16 # 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
17
18
19
20 # 像Stephane Chazelas所l出的那? 一个更Ҏ(gu)理解的等价代码是:
21 route -n |
22 while read des what mask iface; do # 道的输?gu)赋值给?jin)变?
23 echo $des $what $mask $iface
24 done # q将产生Z上边相同的输?
25 # 然? Ulrich Gayer指出 . . .
26 #+ q个单的{h(hun)版本在while循环中用了(jin)一个子shell,
27 #+ 因此当管道结束后, 变量消׃(jin).
28
29
30
31 # 更进一? Filip Moritz解释?jin)上面两个例子之间存在一个细微的不同之处,
32 #+ 如下所C?
33
34 (
35 route -n | while read x; do ((y++)); done
36 echo $y # $y 仍然没有被声明或讄
37
38 while read x; do ((y++)); done < <(route -n)
39 echo $y # $y 的gؓ(f)route -n的输?gu)?
40 )
41
42 # 一般来? (译者注: 原书作者在q里q未加注释符?#", 应该是笔?
43 (
44 : | x=x
45 # 看上L启动?jin)一个子shell
46 : | ( x=x )
47 # ?/p>
48 x=x < <(:)
49 # 其实不是
50 )
51
52 # 当你要解析csv或类g西的时侯, q非常有?
53 # 事实? q就是SuSE的这个代码片断所要实现的功能.
注意事项
[1] q与命名道(临时文g)h相同的作? q且, 事实? 命名道也被同时使用在进E?/p>
替换?