views:

939

answers:

2

How can you diff two pipelines without using temporary files in Bash? Say you have two command pipelines:

foo | bar
baz | quux

And you want to find the diff in their outputs. One solution would obviously be to:

foo | bar > /tmp/a
baz | quux > /tmp/b
diff /tmp/a /tmp/b

Is it possible to do so without the use of temporary files in Bash? You can get rid of one temporary file by piping in one of the pipelines to diff:

foo | bar > /tmp/a
baz | quux | diff /tmp/a -

But you can't pipe both pipelines into diff simultaneously (not in any obvious manner, at least). Is there some clever trick involving /dev/fd to do this without using temporary files?

+11  A: 

A one-line with 2 tmp files (not what you want) would be:

 foo | bar > file1.txt && baz | quux > file2.txt && diff file1.txt file2.txt

With bash, you might try though:

 diff <(foo | bar) <(baz | quux)

As mentioned in the BenM's detailed answer, < creates anonymous named pipes -- managed by bash -- so they are created and destroyed automatically, unlike temporary files.
However, Daniel Cassidy points out the "without using temporary files" part of the question is not respected: the file system is still modified (with a directory entry representing the named pipe created and then removed)

Otherwise, like you mention in your question, you have to use - as STDIN

 foo | bar > file1.txt && baz | quux | diff file1.txt - && rm file1.txt

, since there seems to be no easy way to pipe multiple inputs to one command.

You can only pipe one output to multiple inputs with the tee command:

ls *.txt | tee /dev/tty txtlist.txt

The above command displays the output of ls *.txt to the terminal and outputs it to the text file txtlist.txt.

VonC
+12  A: 

In bash you can use subshells, to execute the command pipelines individually, by enclosing the pipeline within parenthesis. You can then prefix these with < to create anonymous named pipes which you can then pass to diff.

For example:

diff <(foo | bar) <(foo | bar)

The anonymous named pipes are managed by bash so they are created and destroyed automatically (unlike temporary files).

BenM
Much more detailed than my redaction on the same solution -- anonymous batch --. +1
VonC