454

I have two directories with the same list of files. I need to compare all the files present in both the directories using the diff command. Is there a simple command line option to do it, or do I have to write a shell script to get the file listing and then iterate through them?

10 Answers 10

631

You can use the diff command for that:

diff -bur folder1/ folder2/ 

This will output a recursive diff that ignore spaces, with a unified context:

  • b flag means ignoring whitespace
  • u flag means a unified context (3 lines before and after)
  • r flag means recursive
Sign up to request clarification or add additional context in comments.

8 Comments

You can have access to the diff command by downloading the GNU utilities for Win32.
I have also found that --brief option is useful; you get a list of changed files and can process them separately
It's easier to remember this command if you use rub instead of bur i.e. diff -rub folder1/ folder2/
I'd imagine -bur would be easy to remember if you lived in a cold climate.
-urb would also be easy to remember for urban people. Too bad I live in the countryside. I think I'll use -bru ("bru" means "daughter in law", in French).
|
199

If you are only interested to see the files that differ, you may use:

diff -qr dir_one dir_two | sort 

Option "q" will only show the files that differ but not the content that differ, and "sort" will arrange the output alphabetically.

3 Comments

It is great! Also works efficiently - i.e. if a whole sub-directory exist only in one of the dirs, its stops recurring into it and reports only the sub-directory itself (without it successor contents). very nice!!
This is a really good first step: see what, if anything, does differ, and then do a detailed diff on each pair of differing files. One's approach would be wildly different if only one or two files differed versus if dozens of files differed. I could get lost in the output from diffing dozens of files at once!
Also, can include -x PATTERN in command to exclude certain subdirectories. For example, diff -qr repo1 repo2 -x ".git" will compare two directories (repo1 and repo2) but will exclude files in .git folder of respective directories.
29

Diff has an option -r which is meant to do just that.

diff -r dir1 dir2

Comments

19

diff can not only compare two files, it can, by using the -r option, walk entire directory trees, recursively checking differences between subdirectories and files that occur at comparable points in each tree.

$ man diff ... -r --recursive Recursively compare any subdirectories found. ... 

Another nice option is the über-diff-tool diffoscope:

$ diffoscope a b 

It can also emit diffs as JSON, html, markdown, ...

Comments

12

If you specifically don't want to compare contents of files and only check which one are not present in both of the directories, you can compare lists of files, generated by another command.

diff <(find DIR1 -printf '%P\n' | sort) <(find DIR2 -printf '%P\n' | sort) | grep '^[<>]' 

-printf '%P\n' tells find to not prefix output paths with the root directory.

I've also added sort to make sure the order of files will be the same in both calls of find.

The grep at the end removes information about identical input lines.

2 Comments

For systems without printf support in find, like macos, one could try something like diff <(cd DIR1 && find . | sort) <(cd DIR2 && find . | sort) | grep '^[<>]'
For MacOS where find does not support -printf, one can use gfind instead, which can be installed brew install findutils
5

When working with git/svn or multiple git/svn instances on disk this has been one of the most useful things for me over the past 5-10 years, that somebody might find useful:

diff -burN /path/to/directory1 /path/to/directory2 | grep +++ 

or:

git diff /path/to/directory1 | grep +++ 

It gives you a snapshot of the different files that were touched without having to "less" or "more" the output. Then you just diff on the individual files.

Comments

4

If it's GNU diff then you should just be able to point it at the two directories and use the -r option.

Otherwise, try using

for i in $(\ls -d ./dir1/*); do diff ${i} dir2; done 

N.B. As pointed out by Dennis in the comments section, you don't actually need to do the command substitution on the ls. I've been doing this for so long that I'm pretty much doing this on autopilot and substituting the command I need to get my list of files for comparison.

Also I forgot to add that I do '\ls' to temporarily disable my alias of ls to GNU ls so that I lose the colour formatting info from the listing returned by GNU ls.

2 Comments

It's not necessary to use ls: for i in ./dir1/*
@Dennis, funky shortcut. +1. I'm so used to doing command substitution though it's automatic and I just use which ever command I need, e.g. sometimes I'm using find. Using ls also lets me play with the the dir listing more, e.g. reverse time based instead of default sequence.
1

In practice the question often arises together with some constraints. In that case following solution template may come in handy.

cd dir1 find . \( -name '*.txt' -o -iname '*.md' \) | xargs -i diff -u '{}' 'dir2/{}' 

Comments

0

Here is a script to show differences between files in two folders. It works recursively. Change dir1 and dir2.

(search() { for i in $1/*; do [ -f "$i" ] && (diff "$1/${i##*/}" "$2/${i##*/}" || echo "files: $1/${i##*/} $2/${i##*/}"); [ -d "$i" ] && search "$1/${i##*/}" "$2/${i##*/}"; done }; search "dir1" "dir2" ) 

Comments

0

The above answers are superior to this but I did this as an exercise

bc -l <<< $(find dirname -type f -exec sum {} /tmp/{} \; | cut -f1 -d' ' | paste -d- - -) | grep -v 0 

I explained it in full here https://stackoverflow.com/a/79169637/504047

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.