When a command takes filenames as argument, how can I avoid creating temporary files?
Suppose I have a command that takes filenames as arguments, like: diff foo.txt bar.txt
What if instead of actual files, I want to use the results of a command in each?
I can use temporary files:
ls /home/alice > /tmp/alice.txt
ls /home/bob > /tmp/bob.txt
diff alice.txt bob.txt
But what if I don't want to create the files?
2 answers
What you're looking for is called process substitution.
In Bash and many bash-like shells, you can use <(foo_command --with --arguments) instead of the file path:
diff <(ls /home/alice) <(ls /home/bob)
1 comment thread
This other answer uses process substitutions. Not every shell supports this feature. If your OS provides pathnames for file descriptors (/dev/fd/N or /proc/self/fd/N) then you can use them to achieve the desired result without process substitution and without temporary files:
ls /home/alice | { ls /home/bob | diff /dev/fd/4 -; } 4<&0 </dev/null
The result of ls /home/alice would be piped to the next command (group of commands { } in our case) via stdin of the next command, but we make it available as file descriptor 4 (4<&0). We also redirect stdin to /dev/null in case something tries to read from it while it shouldn't. In our case this "something" is the second ls. While ls does not try to read from its stdin, in general a command may.
Now the result of ls /home/alice is available to diff via its file descriptor 4. By passing /dev/fd/4 as an operand we tell diff to use the file (pipe in this case) associated with the descriptor. Note in some systems opening /dev/fd/4 results in duplicating the descriptor (i.e. referring to the same open file description), but in other systems (particularly in Linux) opening /dev/fd/4 results in opening the file anew (i.e. creating a fresh new open file description). In our case this nuance does not matter, our command should work either way.
The result of ls /home/bob is piped to diff via its stdin. By - we tell diff to read from its stdin. Note - means "stdin" only because diff interprets - this way. Not all commands interpret - as "stdin", so in general you may want to use /dev/fd/0.

0 comment threads