6

I want to redirect the output of a command (diff in this case) to a file but only if there is a difference in files I'm comparing. For example, imagine I have three files a, b, and c where a and b are equivalent but a and c are not.

If I do diff a c > output.txt or diff a b > output.txt, regardless of whether there is a difference or not, output.txt will be created. I only want output.txt to be created if there is a diff (i.e, diff returns 1).

I'd want to do something like:

if ! diff a c > /dev/null; then
    diff a c > output.txt
fi

But without running the command twice. I could save the contents of the command like so:

res=$(diff a c)
if [ $? != 0 ]; then
    echo "$res" > output.txt
fi

But then I'm bringing echo into this as a "middle-man", which could potentially raise some issues. How can I redirect output/create a file only if there's output without duplicating code?

  • 1
    I don't see any issue with the echo solution – Jesse_b Jun 14 at 13:10
  • 1
    @Jesse_b I guess I'm being paranoid because of this SO question. While the issues shown here won't really be evident in my example (using diff), it could fail for other commands. I could use the printf solution, but I was just wondering if there was any way to avoid saving to a variable and immediately printing it afterwards – TerryA Jun 14 at 13:18
  • 1
    Yeah if you want to avoid that issue you could use printf or echo -- to specify the end of options. You could also use cat. – Jesse_b Jun 14 at 13:21
  • A simple temporary file? Delete it if not needed or copy in place if needed. – andcoz Jun 14 at 13:30
  • You need to save the output somewhere, if you want to conditionally discard it. Please edit the question to clarify the issues. – muru Jun 14 at 14:13
8

You could call the command once, redirect the output, then remove the output if there were no differences:

diff a c > output.txt && rm output.txt
  • This seems like the most clean solution. Thank you – TerryA Jun 14 at 14:23
7

diff is a relatively expensive command, at least if the files are different. Calculating a minimal set of changes is (relatively) CPU intensive. So its understandable not to want to do that twice.

cmp, however, is cheap, CPU-wise. Presuming these files are of a reasonable size (I doubt you'd call diff on multi-GB files), it will have almost no performance cost—and might even be quicker in the files identical case.

if ! cmp -s a c; then # -s = silent, do not print results to console
    diff a c > output.txt
fi
  • you may want -s instead of --silent. no need to make it needlessly unportable. notice that this q is not tagged linux or coreutils. – Uncle Billy Jun 14 at 16:09
  • @UncleBilly I originally used the long form because it's immediately clear what that option is, but you're right. I switched it to the more-portable version and used a comment instead. Thank you. – derobert Jun 17 at 17:52
5

What about temporary file?

diff a c > /tmp/output.txt
if [ $? != 0 ]; then mv /tmp/output.txt /my/folder/output.txt; else rm -f /tmp/output.txt; fi

replace the -f with -i if you want delete confirmation dialog.

This way you only run command twice, no temporary variables and no 'middleman' be it echo, printf or anything else.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.