使用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)
您能解释一下为什么在输入中使用进程替换的函数的输出不能通过管道使用吗?
我不是在寻找一种解决方法来使我的示例正常工作。我正在寻找一种解释,因为找不到。
FYI sed
在这里不相关,我尝试了其他多个命令(echo,cat ...),并得到了相同的结果
答案 0 :(得分:1)
通过管道传递ncat
函数的输出时,它必须在子shell中运行。由于某种原因,连接到进程替换管道的FD未被此子Shell继承。由于它使用/proc/self/fd
,因此如果未在子进程中打开FD,则尝试从中读取失败。
对我来说,这似乎是个错误,因为在这方面,函数应类似于外部函数。
这不是特定于Linux的,我在运行zsh 5.3的MacOS上重现了该问题。
这似乎仅在为管道创建子外壳时发生。为了查看何时创建子进程以及是否继承了FD,我将函数更改为:
ncat() { echo $$;sh -c 'echo $PPID';echo "$@";ls /dev/fd; }
({/dev/fd
是Mac上的/proc/self/fd
。)
如果我跑步
(ncat <(gzcat myfile.gz ))
括号创建一个子外壳,但与ls /dev/fd
输出中显示的与过程替换 相关的FD。