30

I am trying to find diffs between all files of same names across two copies of a directory (say a working and a backup). For example, I can diff two files of same name in both:

> diff d1/f.cpp d2/f.cpp

or I can find differences across the directories:

> diff d1 d2

but how can I find differences between the *.cpp files only?

> diff d1/*.cpp d2/*.cpp

does not seem to work (for obvious reasons).

[It is probably easy to solve with loops, but I am trying to find a more elegant way]

0

4 Answers 4

69

diff -qr {DIR1} {DIR2} does all files in both directories.

  • q shows only differences
  • r does recursive. Leave it out if you do not need that

You can not tell diff directly to use wildcards but you can add:

-x PAT  --exclude=PAT
    Exclude files that match PAT.

-X FILE    --exclude-from=FILE
   Exclude files that match any pattern in FILE.

to exclude files. So if you only want *.cpp the easiest method is to create a textfile that lists all the files that are not *.cpp. You can do this with the following command: ls -I "*.cpp" > excluded_files where the -I "*.cpp" argument ignores all the .cpp files. Note that the quotation marks are necessary.

1
  • You can add the -s flag to report when two files are the same if you want to feel a sense of reassurance and the number of files isn't too large diff -sr {DIR1} {DIR2}
    – Anil
    Aug 16, 2022 at 14:47
18

You can use a shell loop that runs diff for each file, though this will not catch the cases where d2 contains a file, but d1 doesn't. It might be sufficient though.

for file in d1/*.cpp; do
    diff "$file" "d2/${file##*/}"
done

Or all on one line:

for file in d1/*.cpp; do diff "$file" "d2/${file##*/}"; done

The ${file##*/} part is a special parameter expansion.

If the file variable contains d1/hello.cpp, then "${file##*/}" will expand to hello.cpp (the value of file, but with everything up to, and including, the last / removed).

So "d2/${file##*/}" will result in d2/hello.cpp and the resulting diff command is thus diff d1/hello.cpp d2/hello.cpp

See http://mywiki.wooledge.org/BashFAQ/100 for more on string manipulations in bash.

On a side note, a version control system (such as subversion, git, mercurial etc...) would make this type of diffing much easier.

1
  • I think that of the two great answers, this on is more straight forward when there are multiple file types (although I mentioned in the question that I'm looking for a no-loops solution), so I accepted it. The one addition added is echo "${file##*/}"; before the diff command, so one knows what files are actually being compared. Also, as mentioned in @Rinzwind's answer, this method does not cover the case were the file list is not exactly the same in both directories.
    – ysap
    Dec 23, 2012 at 5:00
7

Some time after asking the question, I found out the meld diff utility, and am using it since then. This is a great piece of GUI based program that makes comparison and merge between files and directory a very easy task. It does two- or three-way compares.

Specifically, it answers my original question in that it shows you a color-coded comparison of the directory contents, and lets you compare specific files by a double-click on the file name.

If one needs more than a three-way comparison, then gvimdiff (based on the vim editor) is a great too as well that provides this functionality.

1

There's a lightweight solution for that:

  1. Set up this tiny plugin http://www.vim.org/scripts/script.php?script_id=5309
  2. Do diff dir1 dir2 | vim -R - at shell

It will add folds and side-by-side comparison for changed files.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .