简体   繁体   中英

Diff output from two programs without temporary files

Say I have too programs a and b that I can run with ./a and ./b .

Is it possible to diff their outputs without first writing to temporary files?

Use <(command) to pass one command's output to another program as if it were a file name. Bash pipes the program's output to a pipe and passes a file name like /dev/fd/63 to the outer command.

diff <(./a) <(./b)

Similarly you can use >(command) if you want to pipe something into a command.

This is called "Process Substitution" in Bash's man page.

Adding to both the answers, if you want to see a side by side comparison, use vimdiff :

vimdiff <(./a) <(./b)

Something like this:

在此输入图像描述

One option would be to use named pipes (FIFOs) :

mkfifo a_fifo b_fifo
./a > a_fifo &
./b > b_fifo &
diff a_fifo b_fifo

... but John Kugelman's solution is much cleaner.

For anyone curious, this is how you perform process substitution in using the Fish shell :

Bash:

diff <(./a) <(./b)

Fish:

diff (./a | psub) (./b | psub)

Unfortunately the implementation in fish is currently deficient ; fish will either hang or use a temporary file on disk. You also cannot use psub for output from your command.

Adding a little more to the already good answers (helped me!):

The command docker outputs its help to STD_ERR (ie file descriptor 2)

I wanted to see if docker attach and docker attach --help gave the same output

$ docker attach

$ docker attach --help

Having just typed those two commands, I did the following:

$ diff <(!-2 2>&1) <(!! 2>&1)

!! is the same as !-1 which means run the command 1 before this one - the last command

!-2 means run the command two before this one

2>&1 means send file_descriptor 2 output (STD_ERR) to the same place as file_descriptor 1 output (STD_OUT)

Hope this has been of some use.

For zsh, using =(command) automatically creates a temporary file and replaces =(command) with the path of the file itself. With normal Process Substitution, $(command) is replaced with the output of the command.

This zsh feature is very useful and can be used like so to compare the output of two commands using a diff tool, for example Beyond Compare:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

For Beyond Compare, note that you must use bcomp for the above (instead of bcompare ) since bcomp launches the comparison and waits for it to complete. If you use bcompare , that launches comparison and immediately exits due to which the temporary files created to store the output of the commands disappear.

Read more here: http://zsh.sourceforge.net/Intro/intro_7.html

Also notice this:

Note that the shell creates a temporary file, and deletes it when the command is finished.

and the following which is the difference between $(...) and =(...) :

If you read zsh's man page, you may notice that <(...) is another form of process substitution which is similar to =(...). There is an important difference between the two. In the <(...) case, the shell creates a named pipe (FIFO) instead of a file. This is better, since it does not fill up the file system; but it does not work in all cases. In fact, if we had replaced =(...) with <(...) in the examples above, all of them would have stopped working except for fgrep -f <(...). You can not edit a pipe, or open it as a mail folder; fgrep, however, has no problem with reading a list of words from a pipe. You may wonder why diff <(foo) bar doesn't work, since foo | diff - bar works; this is because diff creates a temporary file if it notices that one of its arguments is -, and then copies its standard input to the temporary file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM