Skip to content
Advertisement

mixing process substitution and pipes in zsh

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.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement