如何在sh中实现与bash `cat <(echo hello) myfifo` 等效的正确行为
问题原因
你遇到的行为差异是macOS BSD环境下POSIX shell的管道处理逻辑、以及BSD cat 对标准输入和命名管道的EOF处理规则和GNU bash/GNU coreutils的默认行为不一致导致的。
适配方案
方案1:最简实现(适用于首个输入为静态/可直接输出内容的场景)
如果你的首个输入源可以直接输出到标准输出(比如示例中的echo hello),直接拆分命令顺序执行即可,完全兼容所有POSIX shell:
echo hello cat myfifo
行为和原bash命令完全一致:先输出hello,之后阻塞等待myfifo的写入内容,读完myfifo的内容后自动退出。
方案2:通用流式实现(适用于首个输入为任意动态命令输出的场景)
如果需要完全替代bash进程替换 <(cmd)的动态流式输出能力,用临时命名管道做中转是兼容性最高的方案,适配所有macOS版本和POSIX shell:
# 生成临时命名管道路径 tmp_fifo=$(mktemp -u /tmp/tmp_fifo.XXXXXX) mkfifo "$tmp_fifo" # 后台执行源命令,输出写入临时命名管道 echo hello > "$tmp_fifo" & # 按顺序读取临时命名管道和目标命名管道 cat -- "$tmp_fifo" myfifo # 执行完成后清理临时资源 rm -f -- "$tmp_fifo"
方案3:无临时文件管道修复版
如果不想创建临时文件,只需在管道左侧主动关闭标准输入写端,避免BSD cat 残留对标准输入的监听即可正常退出:
{ echo hello; exec <&-; } | cat /dev/fd/0 myfifo
内容的提问来源于stack exchange,提问作者Jlafarga
相关产品推荐
相关产品推荐

