在 zsh 中混合进程替换和管道

mixing process substitution and pipes in zsh

使用 ZSH,我试图将 sed 命令包装到一个函数中,然后使用它,同时将管道与进程替换混合。 让我用一个例子来解释:

$ echo "test text" | gzip > myfile.gz
$ sed $'s,\x1b\[[0-9;]*[a-zA-Z],,g' <(zcat myfile.gz) | more
test text
$ ncat() { sed $'s,\x1b\[[0-9;]*[a-zA-Z],,g' $@; }
$ zcat myfile.gz | ncat | more
test text
$ ncat <(zcat myfile.gz) | more
sed: can't read /proc/self/fd/13: No such file or directory

如您所见,这 3 种用法中的 2 种有效。最后一个是这里引起我兴趣的一个。 (请注意,所有命令都适用于 bash)

您能解释一下为什么在输入中使用进程替换的函数的输出不能通过管道使用吗?

我不是在寻找解决方法来使我的示例正常工作。我正在寻找解释,因为我找不到。

仅供参考 sed 与此处无关,我尝试了多个其他命令(echo、cat...),并得到了相同的结果

当您通过管道传输 ncat 函数的输出时,它必须是 运行 在子 shell 中。由于某种原因,连接到进程替换管道的 FD 没有被这个子 shell 继承。由于它使用 /proc/self/fd,如果 FD 未在子进程中打开,则尝试从中读取失败。

对我来说这似乎是一个错误,因为在这方面函数应该与外部函数类似。

这不是 Linux 特有的,我在 MacOS 运行ning zsh 5.3.

上重现了这个问题

它似乎只有在为管道创建子外壳时才会发生。查看subprocess何时创建,fd是否继承,我把函数改成:

ncat() { echo $$;sh -c 'echo $PPID';echo "$@";ls /dev/fd; }

/dev/fd 相当于 /proc/self/fd 的 Mac。)

如果我运行

(ncat <(gzcat myfile.gz )) 

括号创建了一个子 shell,但是 与进程替换关联的 FD 是 显示在 ls /dev/fd 输出中。