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]


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##*/}"

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.

| improve this answer | |
  • 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 '12 at 5:00

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.

| improve this answer | |
  • Simple, and works flawlessly. – Jose Gómez Dec 14 '16 at 22:25

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.

| improve this answer | |

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.

| improve this answer | |

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.