Using ZSH, I am trying to wrap a sed command into a function, then use it, while mixing pipes with process substution. Let me explain with an example:
$ 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
As you can see, in those 2 out of those 3 usages work. The last one is the one that intrigues me here. (Note that all commands work with bash)
Can you explain why the output of a function that uses process substitution in input, is not usable through a pipe?
I am not looking for a workaround to just make my example work. I am looking for an explanation, because I couldn’t find one.
FYI sed
is not relevant here, I tried with multiple other commands (echo, cat…), and got the same outcome
Advertisement
Answer
When you pipe the ncat
function’s output, it has to be run in a subshell. For some reason, the FD connected to the process substitution pipe is not being inherited by this subshell. Since it uses /proc/self/fd
, if the FD isn’t open in the child process, the attempt to read from it fails.
It seems like a bug to me, since a function should work similarly to external functions in this regard.
This isn’t Linux-specific, I reproduced the problem on MacOS running zsh 5.3.
It only seems to happen when the subshell is created for a pipe. To see when a subprocess is created and whether the FD is inherited, I changed the function to:
ncat() { echo $$;sh -c 'echo $PPID';echo "$@";ls /dev/fd; }
(/dev/fd
is the Mac equivalent of /proc/self/fd
.)
If I run
(ncat <(gzcat myfile.gz ))
The parentheses create a subshell, but the FD associated with the process substitution is shown in the ls /dev/fd
output.