दो निर्देशिकाओं की सामग्री की तुलना करें


92

मेरे पास दो निर्देशिकाएं हैं जिनमें समान फाइलें होनी चाहिए और समान निर्देशिका संरचना होनी चाहिए।

मुझे लगता है कि इन निर्देशिकाओं में से एक में कुछ गायब है।

बैश शेल का उपयोग करना, क्या मेरी निर्देशिकाओं की तुलना करने का एक तरीका है और देखें कि क्या उनमें से एक फाइल गायब है जो दूसरे में मौजूद हैं?


1
का आउटपुट क्या है bash --version?
जॉब

1
समान लेकिन अधिक विशिष्ट: stackoverflow.com/questions/16787916/…
Ciro Santilli 中心 stack stack stack

जवाबों:


63

इस तुलना को करने का एक अच्छा तरीका है , findसाथ में उपयोग करना ।md5sumdiff

उदाहरण

निर्देशिका में सभी फ़ाइलों को सूचीबद्ध करने के लिए खोज का उपयोग करें फिर प्रत्येक फ़ाइल के लिए md5 हैश की गणना करें और फ़ाइल के लिए फ़ाइलनाम द्वारा छाँटे गए पाइप:

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

दूसरी निर्देशिका के लिए भी यही प्रक्रिया करें:

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

फिर परिणाम की तुलना दो फाइलों के साथ करें diff:

diff -u dir1.txt dir2.txt

या प्रक्रिया प्रतिस्थापन का उपयोग कर एक एकल कमांड के रूप में:

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

यदि आप केवल परिवर्तन देखना चाहते हैं:

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

कट कमांड केवल हैश (पहला क्षेत्र) को अंतर से तुलना करने के लिए प्रिंट करता है। अन्यथा डिफरेंशियल हर लाइन प्रिंट करेगा क्योंकि हैश समान होने पर भी डायरेक्टरी पाथ अलग-अलग होते हैं।

लेकिन आपको नहीं पता होगा कि कौन सी फाइल बदली ...

उसके लिए, आप कुछ इस तरह की कोशिश कर सकते हैं

diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2 | sed 's/ .*\// /') <(find /dir2/ -type f -exec md5sum {} + | sort -k 2 | sed 's/ .*\// /')

यह रणनीति बहुत उपयोगी है जब दो निर्देशिकाओं की तुलना एक ही मशीन में नहीं की जाती है और आपको यह सुनिश्चित करने की आवश्यकता है कि फाइलें दोनों निर्देशिकाओं में समान हैं।

नौकरी करने का एक और अच्छा तरीका है Git की diffकमांड का उपयोग करना (जब फ़ाइल की अलग-अलग अनुमतियाँ हो सकती हैं - तो हर फ़ाइल आउटपुट में सूचीबद्ध होती है:

git diff --no-index dir1/ dir2/

1
यह एक अतिरिक्त छँटाई कदम के बिना काम नहीं करता है, क्योंकि जिस क्रम में findफ़ाइलों की सूची होगी, वह दो निर्देशिकाओं के बीच सामान्य रूप से भिन्न होगी।
फहीम मीठा

1
फ़ाइलों को सॉर्ट करने के लिए एक Askubuntu.com/a/662383/15729 में वर्णित विधि का उपयोग कर सकता है ।
फहीम मीठा

1
मुझे त्रुटि मिलती है `` खोजें: md5sum: ऐसी कोई फ़ाइल या निर्देशिका नहीं है
होउमन

1
@ हाउमैन मुझे नहीं पता कि आप किस लिनक्स डिस्ट्रो का उपयोग कर रहे हैं, लेकिन शायद आपको एक पैकेज स्थापित करने की आवश्यकता है जो डे md5sum प्रदान करेगा। फेडोरा 26 में आप इसके साथ इसे स्थापित कर सकते हैं: #dnf स्थापित
कोरुटिल्स

Md5 () का प्रयोग करें
boj

81

आप diffकमांड का उपयोग वैसे ही कर सकते हैं जैसे आप फ़ाइलों के लिए करते हैं:

diff <directory1> <directory2>

यदि आप सबफ़ोल्डर और फ़ाइल्स भी देखना चाहते हैं, तो आप -rविकल्प का उपयोग कर सकते हैं :

diff -r <directory1> <directory2>

2
diffनिर्देशिकाओं के लिए भी काम नहीं करता था (आदमी की पुष्टि की गई है कि), लेकिन यह उप-सीमाओं के अंदर उपनिर्देशिकाओं में परिवर्तन के लिए पुनरावर्ती जाँच नहीं करता है।
जॉब

1
@ जोबन अजीब है ... मेरे लिए, यह काम करता है।
एलेक्स आर।

1
मेरे पास ऐसा कुछ है: a/b/c/d/a, x/b/c/d/b। देखें आपको क्या diff a xदेता है।
नौकरी

2
आपको -rविकल्प का उपयोग करना होगा । वह ( diff -r a x) मुझे देता है:Only in a/b/c/d: a. only in x/b/c/d: b.
एलेक्स आर।

3
अंतर मुझे अंतर दिखाओ फ़ाइलें लेकिन नहीं अगर एक निर्देशिका एक फ़ाइल है कि अन्य एक शामिल नहीं है !!! मुझे फ़ाइल में अंतर जानने की ज़रूरत नहीं है, लेकिन यह भी कि यदि कोई फ़ाइल किसी निर्देशिका में मौजूद है और दूसरे में नहीं है
AndreaNobili

24

आपके द्वारा बैश का उपयोग नहीं किया जा रहा है, आप इसके साथ अंतर का उपयोग कर सकते हैं --briefऔर --recursive:

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

man diffदोनों विकल्पों में शामिल हैं:

-q, --brief
रिपोर्ट केवल जब फाइलें अलग हैं

-r, --recursive
पुनरावर्ती पाया किसी भी उपनिर्देशिका की तुलना करें


13

यहाँ केवल फ़ाइल नाम की तुलना करने के लिए एक विकल्प है, और उनकी सामग्री नहीं:

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

यह लापता फ़ाइलों को सूचीबद्ध करने का एक आसान तरीका है, लेकिन निश्चित रूप से यह एक ही नाम की फाइलों को अलग-अलग नहीं बल्कि अलग-अलग सामग्रियों से पता लगाएगा !

(व्यक्तिगत रूप से मैं अपनी diffdirsस्क्रिप्ट का उपयोग करता हूं , लेकिन यह एक बड़ी लाइब्रेरी का हिस्सा है ।)


3
आप बेहतर प्रक्रिया प्रतिस्थापन का उपयोग करेंगे, अस्थायी फ़ाइलें नहीं ...
mniip

3
ध्यान दें कि यह कुछ विशेष वर्णों के साथ फ़ाइल नामों का समर्थन नहीं करता है, उस स्थिति में आप शून्य-सीमांकक का उपयोग करना चाह सकते हैं जो AFAIK diffअब तक समर्थन नहीं कर रहा है। लेकिन commजो git.savannah.gnu.org/cgit/coreutils.git/commit/… के बाद से इसका समर्थन कर रहा है, इसलिए एक बार जब यह आपके पास एक coreutils की बात आती है, तो आप कर सकते हैं comm -z <(cd folder1 && find -print0 | sort) <(cd folder2 && find -print0 | sort -z)(जिसका आउटपुट आपको आगे प्रारूप में परिवर्तित करना पड़ सकता है) आपको --output-delimiterपैरामीटर और अतिरिक्त टूल का उपयोग करने की आवश्यकता है )।
फक

7

शायद एक विकल्प दो बार rsync चलाने का है:

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

पिछली पंक्ति के साथ, आपको ऐसी फाइलें मिलेंगी जो dir1 में हैं और dir2 में अलग (या गायब) हैं।

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

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
-O, --omit-dir-times        omit directories from --times

आप -nपरिवर्तनों से गुजरने के विकल्प को हटा सकते हैं। वह फ़ाइलों की सूची को दूसरे फ़ोल्डर में कॉपी कर रहा है।

यदि आप ऐसा करते हैं, तो हो सकता है कि -uनई फ़ाइलों को अधिलेखित करने से बचने के लिए , एक अच्छा विकल्प का उपयोग किया जाए ।

-u, --update                skip files that are newer on the receiver

एक-लाइनर:

rsync -rtvcsOu -n --progress /dir1/ /dir2/ && rsync -rtvcsOu -n --progress /dir2/ /dir1/

3

यदि आप प्रत्येक फ़ाइल को विस्तार योग्य और संक्षिप्त करना चाहते हैं, तो आप diff -rVim के आउटपुट को पाइप कर सकते हैं ।

पहले चलो विम को एक तह नियम दें:

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

अब बस:

diff -r dir1 dir2 | vim -

आप हिट कर सकते हैं zoऔर zcखोलने और बंद करने के लिए सिलवटों। विम से बाहर निकलने के लिए, मारा:q<Enter>


3

अजगर में प्राप्त करने के लिए बहुत आसान काम:

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

DIR1और के लिए वास्तविक मूल्यों को प्रतिस्थापित करें DIR2

यहाँ नमूना रन:

$ 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

पठनीयता के लिए, यहां एक-लाइनर के बजाय एक वास्तविक स्क्रिप्ट है:

#!/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")

2
ध्यान दें कि os.listdirकोई विशेष आदेश नहीं देता है। इसलिए सूचियों में अलग-अलग क्रम में समान चीजें हो सकती हैं और तुलना विफल हो जाएगी।
मुरु

1
@muru अच्छा बिंदु, मुझे लगता है कि करने के लिए छँटाई शामिल कर देंगे
सर्गी Kolodyazhnyy

3

सर्गी के जवाब से प्रेरित होकर, मैंने दो निर्देशिकाओं की तुलना करने के लिए अपनी खुद की पायथन स्क्रिप्ट लिखी।

कई अन्य समाधानों के विपरीत यह फाइलों की सामग्री की तुलना नहीं करता है। इसके अलावा यह उपनिर्देशिकाओं के अंदर नहीं जाता है जो निर्देशिकाओं में से एक में गायब हैं। इसलिए आउटपुट काफी संक्षिप्त है और स्क्रिप्ट बड़ी निर्देशिकाओं के साथ तेजी से काम करती है।

#!/usr/bin/env python3

import os, sys

def compare_dirs(d1: "old directory name", d2: "new directory name"):
    def print_local(a, msg):
        print('DIR ' if a[2] else 'FILE', a[1], msg)
    # ensure validity
    for d in [d1,d2]:
        if not os.path.isdir(d):
            raise ValueError("not a directory: " + d)
    # get relative path
    l1 = [(x,os.path.join(d1,x)) for x in os.listdir(d1)]
    l2 = [(x,os.path.join(d2,x)) for x in os.listdir(d2)]
    # determine type: directory or file?
    l1 = sorted([(x,y,os.path.isdir(y)) for x,y in l1])
    l2 = sorted([(x,y,os.path.isdir(y)) for x,y in l2])
    i1 = i2 = 0
    common_dirs = []
    while i1<len(l1) and i2<len(l2):
        if l1[i1][0] == l2[i2][0]:      # same name
            if l1[i1][2] == l2[i2][2]:  # same type
                if l1[i1][2]:           # remember this folder for recursion
                    common_dirs.append((l1[i1][1], l2[i2][1]))
            else:
                print_local(l1[i1],'type changed')
            i1 += 1
            i2 += 1
        elif l1[i1][0]<l2[i2][0]:
            print_local(l1[i1],'removed')
            i1 += 1
        elif l1[i1][0]>l2[i2][0]:
            print_local(l2[i2],'added')
            i2 += 1
    while i1<len(l1):
        print_local(l1[i1],'removed')
        i1 += 1
    while i2<len(l2):
        print_local(l2[i2],'added')
        i2 += 1
    # compare subfolders recursively
    for sd1,sd2 in common_dirs:
        compare_dirs(sd1, sd2)

if __name__=="__main__":
    compare_dirs(sys.argv[1], sys.argv[2])

यदि आप इसे एक फ़ाइल के नाम से सहेजते हैं compare_dirs.py, तो आप इसे Python3.x के साथ चला सकते हैं:

python3 compare_dirs.py dir1 dir2

नमूना उत्पादन:

user@laptop:~$ python3 compare_dirs.py old/ new/
DIR  old/out/flavor-domino removed
DIR  new/out/flavor-maxim2 added
DIR  old/target/vendor/flavor-domino removed
DIR  new/target/vendor/flavor-maxim2 added
FILE old/tmp/.kconfig-flavor_domino removed
FILE new/tmp/.kconfig-flavor_maxim2 added
DIR  new/tools/tools/LiveSuit_For_Linux64 added

PS यदि आपको संभावित परिवर्तनों के लिए फ़ाइल आकार और फ़ाइल हैश की तुलना करने की आवश्यकता है, तो मैंने यहां एक अद्यतन स्क्रिप्ट प्रकाशित की: https://gist.github.com/amakukha/f489cbde2afd32817f8e866cf4n77779


1
धन्यवाद, मैंने gist.github.com/mscalora/e86e2bbfd3c24a7c1784f3d692b1c684 को स्किप करने / अनदेखा करने के लिए एक वैकल्पिक तीसरा परम रेगेक्सप जोड़ा, जैसा कि मुझे आवश्यक था बनाने के लिए:cmpdirs dir1 dir2 '/\.git/'
माइक

0

मैं इस सूची में एक NodeJs विकल्प जोड़ूंगा जो मैंने कुछ समय पहले लिखा है।

dir-तुलना

npm install dir-compare -g
dircompare dir1 dir2

0

मैं एक महान उपकरण का सुझाव देना चाहूंगा जिसे मैंने अभी-अभी खोजा है: एमईएलडी

यह ठीक से काम करता है और सब कुछ आप diffलिनक्स-आधारित सिस्टम पर कमांड के साथ कर सकते हैं , क्या वहाँ एक अच्छा ग्राफिक इंटरफ़ेस के साथ दोहराया जा सकता है! का आनंद लें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.