zsh中添加子shell为何改变管道与here string输出?兼析与bash差异
关于zsh与bash中管道、子shell和here string组合行为差异的解析
问题背景
在zsh 5.9(MacOS)环境下,测试管道(|)、子shell(( ))与here string(<<<)的组合使用时,发现了特殊行为,同时与bash 3.2.57存在明显差异:
测试命令及输出:
- 执行
echo "bbb" | (cat <<<aaa),zsh输出:
aaa
- 执行
echo "bbb" | cat <<<aaa,zsh输出:
bbb aaa
而在bash 3.2.57中,上述两个命令的输出均为aaa。
疑问点:
- zsh中为何子shell的存在会改变此类组合命令的输出?
- zsh与bash对此类命令行为存在差异的原因是什么?
问题解析
1. zsh中子shell改变输出的原因
在zsh里,管道右侧如果是子shell(...),here string<<<aaa会优先接管子shell的标准输入,直接覆盖管道传过来的输入通道,导致cat只能读取aaa。具体来说:
- 带壳场景:
echo "bbb" | (cat <<<aaa)启动子shell后,<<<aaa会把aaa作为cat的唯一标准输入源,管道传过来的bbb被屏蔽,所以只输出aaa。 - 无壳场景:
echo "bbb" | cat <<<aaa里,zsh会把管道输入和here string都作为cat的输入源——cat默认会读取所有可用的标准输入,因此依次输出bbb和aaa。
2. zsh与bash行为差异的原因
核心是两种shell对重定向和管道的优先级处理逻辑不同:
- bash中,here string
<<<的优先级始终高于管道,不管有没有子shell,只要指定了<<<aaa,cat的标准输入就会被aaa独占,管道内容直接被忽略,所以两个命令都只输出aaa。 - zsh则分场景处理:
- 面对简单命令(如直接
cat)时,zsh会合并管道输入和here string作为命令的输入; - 面对子shell时,zsh会让子shell内的here string完全接管标准输入,屏蔽管道传来的内容。
- 面对简单命令(如直接
这种差异是不同shell在设计时,对命令解析顺序、重定向优先级的实现逻辑不同导致的,属于各自shell语法规则的正常差异。
内容的提问来源于stack exchange,提问作者washingweb
相关产品推荐
相关产品推荐

