I have two directories that should contain the same files and have the same directory structure.

I think that something is missing in one of these directories.

Using the bash shell, is there a way to compare my directories and see if one of them is missing files that are present in the other?

share|improve this question
1  
What is the output of bash --version? – jobin Feb 16 '14 at 17:10
1  
up vote 23 down vote accepted

A good way to do this comparison is to use find with md5sum, then a diff.

Example

Use find to list all the files in the directory then calculate the md5 hash for each file and pipe it sorted by filename to a file:

find /dir1/ -type f -exec md5sum {} + | sort -k 2 > dir1.txt

Do the same procedure to the another directory:

find /dir2/ -type f -exec md5sum {} + | sort -k 2 > dir2.txt

Then compare the result two files with diff:

diff -u dir1.txt dir2.txt

Or as a single command using process substitution:

diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2) <(find /dir2/ -type f -exec md5sum {} + | sort -k 2)

This strategy is very useful when the two directories to be compared are not in the same machine and you need to make sure that the files are equal in both directories.

Another good way to do the job is using Git’s diff command:

git diff --no-index dir1/ dir2/
share|improve this answer
1  
This doesn't work without an extra sorting step, because the order in which find will list the files will differ in general between the two directories. – Faheem Mitha Aug 30 '17 at 10:22
1  
One can use the method described in askubuntu.com/a/662383/15729 to sort the files. – Faheem Mitha Aug 30 '17 at 10:48
1  
I get the error ``find: md5sum: No such file or directory – Houman Oct 3 '17 at 13:14
1  
@Houman I don't know what Linux Distro you are using, but perhaps you need to install a package that will provide de md5sum. In Fedora 26 you can install it with: #dnf install coreutils – Adail Junior Oct 4 '17 at 19:05
    
@AdailJunior I'm on Mac Sierra. Thanks – Houman Oct 5 '17 at 12:26

Maybe one option is to run rsync two times

rsync -r -n -t -v --progress -c -s /dir1/ /dir2/

With the previous line, you will get files that are in dir1 and are different (or missing) in dir2. Also folders with different date.

rsync -r -n -t -v --progress -c -s /dir2/ /dir1/

The same for dir2

#from the rsync --help :
-r, --recursive             recurse into directories
-n, --dry-run               perform a trial run with no changes made
-t, --times                 preserve modification times
-v, --verbose               increase verbosity
    --progress              show progress during transfer
-c, --checksum              skip based on checksum, not mod-time & size
-s, --protect-args          no space-splitting; only wildcard special-chars

You can delete the -n option to undergo the changes. That is copying the list of files to the second folder.

In case you do that, maybe a good option is to use -u, to avoid overwriting newer files.

-u, --update                skip files that are newer on the receiver
share|improve this answer

Fairly easy task to achieve in python:

python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' DIR1 DIR2

Substitute actual values for DIR1 and DIR2.

Here's sample run:

$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Desktop
SAME
$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Pictures/
DIFF

For readability, here's an actual script instead of one-liner:

#!/usr/bin/env python
import os, sys

d1 = os.listdir(sys.argv[1])
d2 = os.listdir(sys.argv[2])
d1.sort()
d2.sort()

if d1 == d2:
    print("SAME")
else:
    print("DIFF")
share|improve this answer
2  
Note that the os.listdir doesn't give any specific order. So the lists might have the same things in different order and the comparison would fail. – muru Nov 14 '16 at 6:15
1  
@muru good point, I'll include sorting to that – Sergiy Kolodyazhnyy Nov 14 '16 at 6:17

If you want to make each file expandable and collapsible, you can pipe the output of diff -r into Vim.

First let's give Vim a folding rule:

mkdir -p ~/.vim/ftplugin
echo "set foldexpr=getline(v:lnum)=~'^diff.*'?'>1':1 foldmethod=expr fdc=2" >> ~/.vim/ftplugin/diff.vim

Now just:

diff -r dir1 dir2 | vim -

You can hit zo and zc to open and close folds. To get out of Vim, hit :q<Enter>

share|improve this answer

Here is an alternative, to compare just filenames, and not their contents:

diff <(cd folder1 && find . | sort) <(cd folder2 && find . | sort)

This is an easy way to list missing files, but of course it won't detect files with the same name but different contents!

(Personally I use my own diffdirs script, but that is part of a larger library.)

share|improve this answer
3  
You'd better use process substitution, not temp files... – mniip Feb 16 '14 at 18:03
    
Good suggestion, thanks. – joeytwiddle Feb 17 '14 at 5:16
3  
Note that this does not support file names with certain special characters, in that case you might want to use zero-delimiters which AFAIK diff is not supporting as of now. But there is comm which is supporting it since git.savannah.gnu.org/cgit/coreutils.git/commit/… so once it comes to a coreutils near you, you can do comm -z <(cd folder1 && find -print0 | sort) <(cd folder2 && find -print0 | sort -z) (whose output you might have to further convert in the format you need using the --output-delimiterparameter and additional tools). – phk Mar 5 '16 at 21:52

Through you are not using bash, you can do it using diff with --brief and --recursive:

$ diff -rq dir1 dir2 
Only in dir2: file2
Only in dir1: file1

The man diff includes both options:

-q, --brief
report only when files differ

-r, --recursive
recursively compare any subdirectories found

share|improve this answer

You can use the diff command just as you would use it for files:

diff <directory1> <directory2>

If you want to see subfolders and -files too, you can use the -r option:

diff -r <directory1> <directory2>
share|improve this answer
2  
Didn't know diff works for directories as well(man diff confirmed that), but this doesn't recursively check for changes in subdirectories inside subdirectories. – jobin Feb 16 '14 at 17:04
1  
@Jobin That's strange... For me, it does work. – Alex R. Feb 16 '14 at 17:07
1  
I have something like this: a/b/c/d/a, x/b/c/d/b. See what diff a x gives you. – jobin Feb 16 '14 at 17:09
2  
You have to use the -r option. That (diff -r a x) gives me: Only in a/b/c/d: a. only in x/b/c/d: b. – Alex R. Feb 16 '14 at 17:11
2  
diff show me the difference INTO files but not if a directory contains a file that the other one not contains !!! I don't need know the differences into file but also if a file exist in a directory and not in the other one – AndreaNobili Feb 16 '14 at 17:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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