I want to pipe two programs into one. If my shell supports it, I can use Process substitution. For example, to list the common lines of two files in indifferent order, I can use
comm -12 <(sort a) <(sort b)
However process substitution doesn't exist in plain sh
. I can do it with full POSIX portability by creating a named pipe, but this is cumbersome as it requires finding a directory for the FIFO and cleaning up afterwards. A good practical compromise is to use two shell pipe constructs and use file descriptor shuffling to move one pipe to another file descriptor, then use /dev/fd
to designate the pipe, which works on most Unix variants:
sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }
This works in dash, bash, BusyBox sh, etc. but not in ksh93 and mksh. Why?
$ mksh -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
$ ksh93 -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
comm: /dev/fd/0: No such device or address