Adding a Little Color to Recursive diffs

I have routine need to recursively diff two large directory trees with small changes sprinkled throughout. After staring at pages and pages of one diffed file after another it becomes easy to lose track of what two files' differences I'm looking at.

An easy way to keep track of things is to inject a little color. The way I go about this is:

diff -r old/ new/ | grep --color=always -e '^diff.*' -e '$' | less -R

I pass the output of my recursive diff to grep which I match of every line starting with "diff" -- which happens to be every line starting the output of a new set of files. Also, so that I don't throw away all of the output that doesn't start with "diff" I match on the end of every other line, which allows it to be printed but without being colored.

And since we're talking about pages upon pages of output I pipe everything to less, which would normally try and display the color escape sequences, but with the -R option ANSI color sequences are still output in their raw form so my terminal still displays my coloring.

And suddenly what was a wall of single colored text is a little more readable. If you want to go a step further:
In this case I've done a few of things. I'm now displaying lines with differences side by side. Normally this would also display common lines as well, but I've suppressed that for the sake of the mountain of output it would produce. Also, by default diff will cut off a line after 130 characters. With side by side columns this becomes a serious issue, so I've set the column width to the width of the terminal -- in this case it doesn't make much of a difference because the window is so small. Lastly, all these new options clutter up my "diff" lines so I've used sed to clean the line up a bit.

This is the command I used to achieve the above:
diff -ryW $COLUMNS --suppress-common-lines la lb | grep --color=always -e '^diff.*' -e '$' |
  sed 's/-ryW.*--suppress-common-lines //' | less -R

The new options:

  • -y Output lines side by side
  • -W $COLUMNS sets the width of output to the width of the terminal, you may have to use tput cols if you're not using BASH
  • --suppress-common-lines prevents every line from being printed when using side by side output

Tags: