The question in the current bounty notice:
the general example is too complicated. Can somebody please explain how to implement following example? diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)
seems to have an answer here.
As shown in Gilles' answer, the general idea is to send the output of "producer" commands to new device files1 at different stages of a pipeline, making them available to "consumer" commands, which may possibly take file names as arguments (assuming that your system gives you access to file descriptors as /dev/fd/X
).
The simplest way to achieve what you are looking for is probably:
xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0
(Using file1.xz
in place of "$1"
for readability and xz -cd
instead of cat ... | xz -d
because a single command is enough).
The output of the first "producer" command, xz -cd file1.xz
, is piped to a compound command ({...}
); but, instead of being consumed immediately as the standard input of the next command, it is duplicated to file descriptor 3
and thus made accessible to everything inside the compound command as /dev/fd/3
. The output of the second "producer" command, xz -cd file2.xz
, which does consume neither its standard input nor anything from file descriptor 3
, is then piped to the "consumer" command diff
, which reads from its standard input and from /dev/fd/3
.
Piping and file descriptor duplication may be added in order to provide device files for as many "producer" commands as needed, e.g.:
xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0
While it may be irrelevant in the context of your specific question, it is worth noting that:
cmd1 <(cmd2) <(cmd3)
, cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0
and ( cmd2 | ( cmd3 | ( cmd1 /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
have different potential effects on the initial execution environment.
Contrary to what happens in cmd1 <(cmd2) <(cmd3)
, cmd3
and cmd1
in cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0
will not be able to read any input from the user. That will require further file descriptors. For instance, to match
diff <(echo foo) <(read var; echo "$var")
you will need something like
{ echo foo | { read var 0<&9; echo "$var" | diff /dev/fd/3 -; } 3<&0; } 9<&0
1 More on them can be found on U&L, e.g. in Understanding /dev and its subdirs and files.
bash
on your device? – Arkadiusz Drabczyk Aug 07 '19 at 10:27/dev/fd
and usingxz -cd <file>
instead ofcat <file> | xz -d
) could bexz -cd "$1" | { xz -cd "$2" | { diff /dev/fd/3 /dev/fd/4; } 3<&0; } 4<&0
. – fra-san Aug 07 '19 at 12:26