Do you need an anonymous pipe in your bash script, to connect some processes to?

If you are on macOS, sorry, you'll make to create a named fifo (you'll get a permission error if you try the code below), but if you're on Linux it's easy-peasy by abusing the process substitution syntax:

$ exec {FD}<> >(:) $ echo weeee >&$FD $ head -n 1 <&$FD weeee

I don't know if that creates an unnecessary subprocess that immediately terminates. Probably. But if you care about that, why are you even doing this in bash?

If you create two pipes, you can connect one to the stdin of a subprocess, one to the stdout, and boom, you've emulated the coproc functionality. It won't have the nice process management going on, though:

$ exec {PIPER}<> >(:) {PIPEW}<> >(:) $ grep --line-buffered bar <&$PIPER >&$PIPEW & [3] 14753 $ echo foo >&$PIPER $ echo bar >&$PIPER $ echo baz >&$PIPER $ head -n 1 <&$PIPEW bar $ exec {PIPER}>&- {PIPEW}>&- $ ps p 14753 PID TTY STAT TIME COMMAND 14753 pts/1 S 0:00 grep --color=auto --line-buffered bar

Yeah, so remember to close that subprocess before you leave.
This relies on some surprising interaction between anonymous pipes and open(). When you call pipe() or pipe2(), it outputs two FDs for you to use -- one readable, one writeable. But then if you open() the /proc/<pid>/fd/<FD> for one of them with mode O_RDWR, boom, Linux gives you both ends of the pipe on one FD.

I wonder if there is software out there that dared rely on this quirk.

Here's an illustration using execline piperw(0):

$ piperw 41 43 bash -c 'ls -l /proc/$$/fd -l; exec 42<>/proc/$$/fd/41; ls /proc/$$/fd -l' [ . . . ] lr-x------ 1 clacke clacke 64 Mar 10 14:30 41 -> 'pipe:[1153564]' l-wx------ 1 clacke clacke 64 Mar 10 14:30 43 -> 'pipe:[1153564]' [ . . . ] lr-x------ 1 clacke clacke 64 Mar 10 14:30 41 -> 'pipe:[1153564]' lrwx------ 1 clacke clacke 64 Mar 10 14:30 42 -> 'pipe:[1153564]' l-wx------ 1 clacke clacke 64 Mar 10 14:30 43 -> 'pipe:[1153564]'


So anyway, today I've been reading bash parse.y, redir.c, make_cmd.c and execute_cmd.c for hours to settle a fringe conversation on stackoverflow. 😁

I also learned that process substitution has been in bash from the very first commit in the git repository, which is the import of the tarball for bash 1.14.7, from August 1996. Back then bash used the GPLv1 for license, which is interesting in itself, because the GPLv2 was released already in June 1991. Maybe there's a story there.

@clacke Think of the show potential!! I have co-processes on my list for Bash Tips, but way out in the future.

@perloid I very much thought of the #HPREp potential as I was writing this. Good to know there is no duplication of effort if I get it up reasonably soon.
@perloid As I started reading release notes I remembered that you had mentioned differences between bash versions as a far-future project as well.

@clacke Indeed. With the recent arrival of version 5 I'd been looking at differences there, but my roadmap, though a bit vague at present, is aimed at redirection , pipes, functions and similar in the short to medium term.

Sign in to participate in the conversation
Mastodon @ SDF

"I appreciate SDF but it's a general-purpose server and the name doesn't make it obvious that it's about art." - Eugen Rochko