1. 管道中子shell导致变量赋值失效
在bash脚本中,管道(|)是一个非常常用的工具,它把一个命令的标准输出连接到下一个命令的标准输入。然而,管道有一个隐蔽的陷阱:管道中的每个命令都在子shell中执行。这意味着任何在管道中进行的变量赋值,在管道结束后都会被丢弃。
最典型的例子就是read命令:
echo"foo"|readecho$REPLY直觉上我们期望输出foo,但实际上$REPLY是空的。原因就在于echo "foo" | read中的read运行在子shell中,当子shell退出时,它对变量REPLY的修改也随之消失,父shell中的REPLY从未被改变。
2. 进程替换的两种形式:<(…)和>(…)
bash提供了一种特殊的扩展——进程替换(Process Substitution),可以解决上述问题。它允许我们把一个子shell的输出(或输入)当作一个文件名来处理。进程替换有两种形式:
- 用于产生标准输出:
<( list ) - 用于接受标准输入:
>( list )
其中list是一组命令。这两种语法在bash中会被展开成一个临时文件路径(通常是/dev/fd/...),供外部命令进行重定向。
3. 把进程替换当作文件使用
进程替换的核心思想是:将命令的输出伪装成一个文件。由于它是一个扩展,我们可以用echo查看其真实值:</