You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Fish Shell中将标准输出重定向到多个命令?

Fish与Bash进程替换差异导致命令挂起的原因及解决方案

问题背景

在Bash环境中,我们可以通过tee配合进程替换>(...),将同一份标准输出分发到多个命令,实现从JSON中提取不同字段并保存到不同文件的需求,示例如下:

echo '{"foo": "bar", "baz": "bam"}' | tee >(jq -r '.foo' > foo.txt) >(jq -r '.baz' > baz.txt)

执行后foo.txt会写入bar,baz.txt会写入bam,同时原JSON内容也会输出到终端,全程正常运行。

但在Fish中执行类似命令时,会出现命令挂起、卡住不动的情况:

echo '{"foo": "bar", "baz": "bam"}' | tee >(jq '.foo' > foo.txt) >(jq '.bar' > bar.txt)

核心差异:进程替换的实现逻辑

Fish与Bash的进程替换机制存在本质区别,这是导致命令挂起的根本原因:

  • Bash:>(...)创建的是匿名管道,tee完成所有管道的数据写入后就直接退出,不需要等待管道另一端的命令执行完毕。即使后续命令仍在处理数据,tee也不会被卡住。
  • Fish:>(...)本质是创建命名管道(FIFO),tee会等待所有FIFO的读取操作完全完成后才会退出。如果某个进程替换中的命令没有彻底读取FIFO中的数据,或者多FIFO场景下同步等待逻辑触发,整个命令就会一直处于挂起状态。

简言之:Bash是异步分发数据,Fish是同步等待所有接收方处理完成才结束流程。

解决办法

针对Fish的特性,有两种实用的处理方式:

1. 给进程替换内的命令添加后台运行符&

让每个进程替换中的命令后台执行,这样tee无需等待它们完成即可正常退出:

echo '{"foo": "bar", "baz": "bam"}' | tee >(jq -r '.foo' > foo.txt &) >(jq -r '.baz' > baz.txt &)

2. 用jq一次性提取所有字段,再拆分输出

避免使用多个进程替换,先用jq按顺序输出需要的字段,再通过head/tail拆分到不同文件:

echo '{"foo": "bar", "baz": "bam"}' | jq -r '.foo, .baz' | tee >(head -n1 > foo.txt) >(tail -n1 > baz.txt)

另外注意:示例中存在字段名错误(.bar应为.baz),虽然这不是挂起的直接原因,但正确的字段名能避免不必要的输出异常。


内容的提问来源于stack exchange,提问作者Kurt Peek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:15:34