过程替换
虽然它们看起来很相似,并且都可以用来组合流以进行重定向,但组命令和子 shell 之间有一个重要的区别。 组命令在当前 shell 中执行其所有命令,而子 shell(顾名思义)在当前 shell 的子副本中执行其命令。 这意味着环境被复制并提供给shell 的一个新实例。 当子shell退出时,环境的副本将丢失,因此对子shell的环境所做的任何更改(包括变量赋值)也将丢失。 因此,在大多数情况下,除非脚本需要子 shell,否则组命令比子 shell 更可取。 组命令既更快又需要更少的内存。
我们在第 28 章看到了一个子 shell 环境问题的例子,当时我们发现一个 读 管道中的命令并不像我们直观预期的那样工作。 回顾一下,如果我们构建这样的管道:
echo "foo" | 读回声 $REPLY
echo "foo" | 读回声 $REPLY
的内容 回复 变量总是空的,因为 读 命令在子shell中执行,它的副本 回复 当子shell终止时被销毁。
因为管道中的命令总是在子 shell 中执行,任何分配变量的命令都会遇到这个问题。 幸运的是,shell 提供了一种奇特的扩展形式,称为 过程替代 可用于解决此问题。
进程替换以两种方式表示: 对于产生标准输出的进程:
<(名单)
或者,对于接收标准输入的进程:
>(名单)
协调 名单 是一个命令列表。
为了解决我们的问题 读,我们可以像这样使用进程替换:
读 < <(echo "foo") echo $REPLY
读 < <(echo "foo") echo $REPLY
进程替换允许我们将子shell 的输出视为用于重定向的普通文件。 事实上,既然它是一种扩展形式,我们可以考察它的真正价值:
[me@linuxbox ~]$ echo <(echo "foo")
/开发/fd/63
[me@linuxbox ~]$ echo <(echo "foo")
/开发/fd/63
通过使用 回音 查看扩展的结果,我们看到子shell的输出是由一个名为的文件提供的 /开发/fd/63.
进程替换通常与包含以下内容的循环一起使用 读. 这是一个例子
处理由子shell创建的目录列表内容的读取循环:
#!/斌/庆典
# pro-sub:进程替换演示
而读取 attr 链接所有者组大小日期时间文件名; 做猫<<- EOF
文件名:$filename 大小:$size
所有者:$owner
组:$group 修改:$date $time 链接:$links 属性:$attr
EOF
完成 < <(ls -l | tail -n +2)
#!/斌/庆典
# pro-sub:进程替换演示
而读取 attr 链接所有者组大小日期时间文件名; 做猫<<- EOF
文件名:$filename 大小:$size
所有者:$owner
组:$group 修改:$date $time 链接:$links 属性:$attr
EOF
完成 < <(ls -l | tail -n +2)
循环执行 读 对于目录列表的每一行。 列表本身是在脚本的最后一行生成的。 此行将进程替换的输出重定向到循环的标准输入。 这 尾巴 命令包含在进程替换管道中以消除列表的第一行,这是不需要的。
执行时,脚本会产生如下输出:
[我@linuxbox ~]$ 亲子| 头-n 20
文件名:addresses.ldif 大小:14540
业主:我
组:我
Modified: 2009-04-02 11:12
[我@linuxbox ~]$ 亲子| 头-n 20
文件名:addresses.ldif 大小:14540
业主:我
组:我
Modified: 2009-04-02 11:12
链接
1
链接
属性:-rw-r--r--
文件名:bin
大小:4096
业主:我
组:我
Modified: 2009-07-10 07:31
链接:2
属性:drwxr-xr-x
文件名:bookmarks.html 大小:394213
业主:我
组:我
属性:-rw-r--r--
文件名:bin
大小:4096
业主:我
组:我
Modified: 2009-07-10 07:31
链接:2
属性:drwxr-xr-x
文件名:bookmarks.html 大小:394213
业主:我
组:我