命令1:进程替换 + 重定向:
cat test-comm > >(while read line; do echo "A"$line; done)
命令2:传统管道:
cat test-comm | while read line; do echo "A"$line; done
这俩有什么区别?
再说请这个问题前,需要先介绍一下什么是进程替换 和管道。
进程替换的基本概念
进程替换 <(command) 会将命令的输出作为一个临时文件(实际上是命名管道)提供给另一个命令使用。
进程替换的优势
-
无需临时文件:不需要手动创建、管理、删除临时文件
-
更简洁:一行命令完成复杂操作
-
更安全:避免临时文件命名冲突或权限问题
-
性能更好:数据通过管道传递,不需要磁盘I/O
其他进程替换用法
除了 <(...) 用于读取,还有 >(...) 用于写入
POSIX 标准状态
-
<(...)是 Bash/Zsh/Ksh 的扩展功能,不是 POSIX 标准 -
在需要严格 POSIX 兼容的脚本中应避免使用
-
可以使用临时文件或命名管道作为替代方案
-
在实际脚本中可以通过特性检测来提供回退方案
Bash版本要求
-
最低要求:Bash 2.04 或更高版本
-
完全稳定:Bash 3.0 及以后版本支持得更好
"传统管道"和"进程替换 + 重定向"的区别
1. 执行时机和异步性
命令1(进程替换):
-
进程替换
>(...)在子shell中异步执行 -
cat命令完成后,while循环可能还在运行 -
整个命令立即返回,不等待while循环结束
命令2(管道):
-
管道是同步执行
-
cat和while在同一管道中顺序执行 -
整个管道完成后才返回
2. 退出状态码
命令1:
bash
cat test-comm > >(while read line; do echo "A"$line; done)
echo $? # 只反映 cat 命令的退出状态,不反映while循环的状态
命令2:
bash
cat test-comm | while read line; do echo "A"$line; done
echo $? # 反映整个管道中最后一个命令的退出状态
3. 变量作用域
命令1:
bash
# 在进程替换中设置的变量不会影响父shell
count=0
cat test-comm > >(while read line; do echo "A"$line; ((count++)); done)
echo "计数: $count" # 输出: 计数: 0 (不会改变)
命令2:
bash
# 在管道中设置的变量也不会影响父shell(管道也在子shell中运行)
count=0
cat test-comm | while read line; do echo "A"$line; ((count++)); done
echo "计数: $count" # 输出: 计数: 0 (不会改变)
cat test-comm > >(command)和cat test-comm >(command)的区别
除了"传统管道"可以传递数据外,还有"重定向"也就是>符号。可以覆盖(>)或者追加(>>)数据到文件。这里的> >又是啥意思呢?
其实这里第一个>是重定向符号,第二个>是"进程替换"语法的一部分,也就是>(command)的一部分。平常我们对>(command)可以认为成一个临时文件即可。因为>(command) 创建一个临时文件名(通常是 /dev/fd/63 这样的文件描述符)。
cat test-comm > >(command)的含义是,读取test-comm的内容写入到后面的临时文件,也就是传递给>(command)中command去处理。
cat test-comm >(command)的含义是,读取test-comm文件和>(command)临时文件。仅此而已。