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
You are accessing this answer with a direct link, so it's being shown above all other answers regardless of its score. You can return to the normal view.
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
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)
0 comment threads