एक निर्देशिका में मौजूद फ़ाइलों का पता लगाएं, लेकिन दूसरे में नहीं [बंद]


295

मैं एक निर्देशिका में मौजूद फ़ाइलों को खोजने की कोशिश कर रहा हूं, लेकिन दूसरे में नहीं, मैंने इस कमांड का उपयोग करने की कोशिश की है:

diff -q dir1 dir2

उपरोक्त आदेश है कि यह दोनों फ़ाइलों को पाता है के साथ समस्या में dir1नहीं बल्कि में dir2अच्छी तरह से फाइल के रूप में के रूप में dir2नहीं बल्कि में dir1,

मैं फाइलों को खोजने की कोशिश कर रहा हूं dir1लेकिन dir2केवल में नहीं ।

यहाँ एक छोटा सा नमूना है कि मेरा डेटा कैसा दिखता है

dir1    dir2    dir3
1.txt   1.txt   1.txt
2.txt   3.txt   3.txt
5.txt   4.txt   5.txt
6.txt   7.txt   8.txt

मेरे दिमाग पर एक और सवाल यह है कि मैं में फ़ाइलों को मिल सकती है dir1, लेकिन नहीं में dir2या dir3एक भी आदेश में?

जवाबों:


390
diff -r dir1 dir2 | grep dir1 | awk '{print $4}' > difference1.txt

स्पष्टीकरण:

  • diff -r dir1 dir2 दिखाता है कि कौन सी फाइलें केवल dir1 में हैं और जो केवल dir2 में हैं और साथ ही दोनों निर्देशिकाओं में मौजूद फाइलों के परिवर्तनों को यदि कोई है।

  • diff -r dir1 dir2 | grep dir1 दिखाता है कि कौन सी फाइलें केवल dir1 में हैं

  • awk केवल फ़ाइल नाम मुद्रित करने के लिए।


5
मैं यह सुनिश्चित करने के grepलिए चाहूँगा ^dir1कि मुझे dir1बाद में मार्ग में आने का अवसर न मिले ।
एल्फ

@ इसे सुधारें। मैं $4एक उदाहरण के रूप में उपयोग करता हूं । तथ्यों में, मेरे वास्तविक उबंटू पर, diffइतालवी में उत्तर। $4इटालियन और अंग्रेजी उत्तरों के लिए ठीक है, लेकिन मैं हर दूसरी भाषाओं के लिए निश्चित नहीं हूं ...
asclepix

139

यह काम करना चाहिए:

diff -rq dir1 dir2

समझाया गया विकल्प (अंतर के माध्यम से (1) मैन पेज ):

  • -r - किसी भी उपनिर्देशिका की पुनरावृत्ति की तुलना करें।
  • -q - आउटपुट केवल यह है कि क्या फाइलें अलग हैं।

8
अच्छा! लेकिन मुझे लगता है कि इसे इस तरह बढ़ाया जाना चाहिए:diff -rq dir1 dir2 | grep 'Only in dir1/'
sobi3ch

2
यह सामग्री द्वारा तुलना की जाती है, लेकिन धीमे ड्राइव पर लंबा समय लग सकता है।
स्मिटरलिंक

5
-qविकल्प पर सिर्फ एक नोट : आदमी पृष्ठों को केवल "आउटपुट केवल यह बताता है कि फाइलें अलग हैं", न कि यह जांचता है कि क्या वे अलग हैं। मैंने स्रोत कोड का दुरुपयोग किया और पाया कि यह केवल अंतर को निर्धारित करने के लिए फ़ाइल आकार की जाँच करता है, वास्तविक सामग्री का नहीं।
ryancdotnet

-qविकल्प के संबंध में मैं यह नहीं कह सकता कि यह केवल फ़ाइल आकार की जाँच करता है। GNU डिफुटिल्स 3.7 का उपयोग करते हुए एक ही फाइल के आकार के साथ दो फाइलों की तुलना की गई लेकिन diff -q file1 file2आउटपुट के साथ अलग सामग्री Files file1 and file2 differ
स्टीफन श्मिट

50
comm -23 <(ls dir1 |sort) <(ls dir2|sort)

यह कमांड आपको उन फाइलों को देगा जो dir1 में हैं और dir2 में नहीं

<( )साइन के बारे में , आप इसे 'प्रक्रिया प्रतिस्थापन' के रूप में गूगल कर सकते हैं।


यह उपनिर्देशिकाओं के साथ भी काम करना ठीक होगा, मुझे लगता (ls -R dir1|sort)है कि चाल
ulkas

1
यह OS X रिकवरी मोड पर काम करेगा।
एंथनी वनओवर

@ulkas, यदि आप उपयोग करते हैं तो आउटपुट गलत हो सकता है (ls -R dir|sort)
एंड्री मकुक्खा

3
vimdiff रंग हाइलाइटिंग के साथ एक बहुत अच्छे दृश्य की तुलना प्रदान करता है:vimdiff <(ls dir1 |sort) <(ls dir2|sort)
लोगान रीड

32

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

उदाहरण:

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

find /dir1/ -type f -exec md5sum {} \; > dir1.txt

उसी प्रक्रिया को दूसरी निर्देशिका में करें:

find /dir2/ -type f -exec md5sum {} \; > dir2.txt

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

diff dir1.txt dir2.txt

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

काम करने का एक और अच्छा तरीका गिट का उपयोग करना है

git diff --no-index dir1/ dir2/

सादर!


1
मैं नहीं गया git मनमाना निर्देशिकाओं पर एक अंतर कर सकता है जो कि git repo के अंदर नहीं है ... भयानक !!! इस जवाब ने मेरे लिए एक बड़ी समस्या हल कर दी, धन्यवाद
विक्टरनोवा

17

Meld ( http://meldmerge.org/ ) निर्देशिकाओं और फाइलों के भीतर तुलना करने में बहुत अच्छा काम करता है।

निर्देशिकाओं की तुलना करें


मेल्ड एंड को छोड़कर जब यह लाइन एंडिंग की बात करता है तो एक घटिया काम करता है ...
0xC0000022L

1
लाइन एंडिंग की समस्या कभी नहीं हुई। क्या आप विस्तार कर सकते हैं?
कैटालिन हिटरकू

हाँ, यह लाइन अंत का संकेत नहीं देता है। यह (बार-बार) डेवलपर्स को इस उपकरण का उपयोग करने के लिए प्रेरित करता है, जो उदाहरण के लिए, CRLFF में CRLF बनाकर लाइन अंत को "निश्चित" करता है।
0xC0000022L

3
यह फ़ाइल सामग्री को पढ़ने पर भी जोर देता है, और इसलिए >> 1GB निर्देशिका के साथ लगभग बेकार है।
टॉमिस्लाव नैक-अल्फेयरविक

13

निर्देशिकाओं की तुलना करने के लिए vim का डिर्डडिफ़ प्लगइन एक और बहुत ही उपयोगी उपकरण है।

vim -c "DirDiff dir1 dir2"

यह न केवल सूचीबद्ध करता है कि कौन सी फाइलें निर्देशिकाओं के बीच भिन्न हैं, बल्कि आपको उन फाइलों का निरीक्षण करने / संशोधित करने की भी अनुमति देता है जो अलग हैं।


11

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

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

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

नमूना उपयोग:

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

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

user@laptop:~$ python3 compare_dirs.py dir2/ dir1/ | grep dir1
DIR  dir1/out/flavor-domino added
DIR  dir1/target/vendor/flavor-domino added
FILE dir1/tmp/.kconfig-flavor_domino added

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


सरल पर्याप्त स्क्रिप्ट जो वास्तव में मैं चाहता था: एक थोक प्रतिलिपि सत्यापित करें: +1 मुझसे। (हालांकि python2 में परिवर्तित करने के लिए neeed) संकेत: सेट का उपयोग अलग भाग को सरल बना सकता है।
जेसन मॉर्गन

6

एक और (शायद बड़ी निर्देशिकाओं के लिए तेज़) दृष्टिकोण:

$ find dir1 | sed 's,^[^/]*/,,' | sort > dir1.txt && find dir2 | sed 's,^[^/]*/,,' | sort > dir2.txt
$ diff dir1.txt dir2.txt

sedआदेश पहले निर्देशिका घटक को हटा Erik`s पोस्ट करने के लिए धन्यवाद )


1
मेरा मानना ​​है कि यह विधि सरल है (फिर भी findएक टिप्पणी का उपयोग करते हुए और एक अलग उत्तर नहीं): cd dir2; find . -exec [ -e ../dir1/{} ] \; -o -print 2>/dev/null यह dir2 में मौजूद फाइलों को प्रिंट करेगा लेकिन dir1 में मौजूद नहीं है।
अलेक्जेंडर एमेलकिन

5

यह थोड़ा देर से है लेकिन किसी की मदद कर सकता है। यकीन नहीं है कि अगर अंतर या rsync इस तरह नंगे प्रारूप में सिर्फ फ़ाइल नाम बाहर थूकते हैं। उस अच्छे समाधान को देने के लिए plhn का धन्यवाद, जिसका मैंने नीचे विस्तार किया।

यदि आप केवल फ़ाइल नाम चाहते हैं, तो यह आसान है कि आप एक साफ प्रारूप में अपनी जरूरत की फाइलों को कॉपी करें, आप खोज कमांड का उपयोग कर सकते हैं।

comm -23 <(find dir1 | sed 's/dir1/\//'| sort) <(find dir2 | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

यह मानता है कि dir1 और dir2 दोनों एक ही मूल फ़ोल्डर में हैं। sed सिर्फ मूल फ़ोल्डर को निकालता है ताकि आप सेब के साथ सेब की तुलना कर सकें। अंतिम सेड सिर्फ dir1 नाम को वापस रखता है।

यदि आप केवल फाइलें चाहते हैं:

comm -23 <(find dir1 -type f | sed 's/dir1/\//'| sort) <(find dir2 -type f | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

इसी तरह निर्देशिकाओं के लिए:

comm -23 <(find dir1 -type d | sed 's/dir1/\//'| sort) <(find dir2 -type d | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

1
ध्यान दें कि आप उपयोग करने cdके findबजाय पहले कर सकते हैं sed, जैसे comm -23 <(cd dir1 || exit; find -type f | sort) <(cd dir2 || exit; find -type f | sort):। ( exitS findवर्तमान निर्देशिका का उपयोग करने से रोकने के लिए cdअसफल होना चाहिए यहाँ हैं।)
phk

यह भी ध्यान दें कि कुछ विशेष वर्णों वाली फाइलें मौजूद होने पर आपका समाधान विफल हो सकता है, यदि आपके पास commसमर्थन के साथ बहुत हालिया संस्करण है -z( git.savannah.gnu.org/cgit/coreutils.git/commit/… के साथ आया ) तो आप कर सकते हैं comm -23 -z <(cd dir1 && find -type f -print0 | sort -z) <(cd dir2 && find -type f -print0 | sort -z)। (इस बीच मैंने यह भी पता लगा लिया कि exitएस को प्रतिस्थापित किया जा सकता है।)
phk

5

स्वीकृत उत्तर उन फ़ाइलों को सूचीबद्ध करेगा जो दोनों निर्देशिकाओं में मौजूद हैं, लेकिन उनकी सामग्री अलग है। केवल उन फ़ाइलों को सूचीबद्ध करने के लिए जो dir1 में मौजूद हैं, जिनका आप उपयोग कर सकते हैं:

diff -r dir1 dir2 | grep 'Only in' | grep dir1 | awk '{print $4}' > difference1.txt

स्पष्टीकरण:

  • diff -r dir1 dir2: तुलना करें
  • grep 'Only in': उन पंक्तियों को प्राप्त करें जिनमें 'केवल' हों
  • grep dir1: ऐसी लाइनें प्राप्त करें जिनमें dir हो

5

यह उत्तर -Dविकल्प को जोड़कर @ Adail-Junior के उन सुझावों में से एक का अनुकूलन करता है, जो तब मददगार होता है, जब किसी भी निर्देशिका की तुलना नहीं की जा रही है:

git diff -D --no-index dir1/ dir2/

यदि आप उपयोग करते हैं -Dतो आपको तुलना नहीं दिखाई देगी /dev/null: text Binary files a/whatever and /dev/null differ


दो निर्देशिकाओं की तुलना करने में बहुत उपयोगी था, आप फ़ाइलों के बीच अंतर को तुरंत देखते हैं। बेशक पाठ सामग्री के साथ फ़ाइलों पर सबसे अच्छा काम कर रहा है।
एरच कुएस्टर

1

DIFF कमांड का उपयोग करके 2 निर्देशिकाओं की तुलना करने का एक सरल तरीका

diff filename.1 filename.2> filename.dat >> दर्ज करें

रन पूरा होने के बाद filename.dat खोलें

और आप देखेंगे: केवल filename.1: filename.2 में केवल: directory_name: name_of_file1 केवल in: directory_Name: name_of_file2


आपको .dat फ़ाइल में आउटपुट क्यों करना है?
विष्णु एनके

1

यह दो निर्देशिकाओं को समन्वयित करने के लिए कमांड प्रिंट करने के लिए बैश स्क्रिप्ट है

dir1=/tmp/path_to_dir1
dir2=/tmp/path_to_dir2
diff -rq $dir1 $dir2 | sed -e "s|Only in $dir2\(.*\): \(.*\)|cp -r $dir2\1/\2 $dir1\1|" |  sed -e "s|Only in $dir1\(.*\): \(.*\)|cp -r $dir1\1/\2 $dir2\1|" 

0

जीएनयू grepविकल्प के साथ खोज को उलटा कर सकता है -v। यह grepउन लाइनों की रिपोर्टिंग करता है, जो मेल नहीं खाते। इसके द्वारा आप फाइलों dir2को सूची की फाइलों से हटा सकते हैं dir1

grep -v -F -x -f <(find dir2 -type f -printf '%P\n') <(find dir1 -type f -printf '%P\n')

विकल्प -F -xबता grepपूरी लाइन पर एक स्ट्रिंग खोज करने के लिए।

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