यह बताने के लिए सबसे तेज़ तरीका है कि क्या दो फ़ाइलों में यूनिक्स / लिनक्स में समान सामग्री है?


231

मेरे पास एक शेल स्क्रिप्ट है जिसमें मुझे यह जांचने की आवश्यकता है कि दो फाइलों में एक ही डेटा है या नहीं। मैं बहुत सारी फ़ाइलों के लिए ऐसा करता हूं, और मेरी स्क्रिप्ट में diffकमांड को प्रदर्शन अड़चन लगता है।

यहाँ लाइन है:

diff -q $dst $new > /dev/null

if ($status) then ...

क्या फ़ाइलों की तुलना करने का एक तेज़ तरीका हो सकता है, शायद डिफ़ॉल्ट के बजाय एक कस्टम एल्गोरिथ्म diff?


10
यह वास्तव में नाइटपैकिंग है, लेकिन आप यह देखने के लिए नहीं कह रहे हैं कि क्या दो फाइलें समान हैं, आप पूछ रहे हैं कि क्या दो फाइलों में समान सामग्री है। समान फ़ाइलों में समान इनोड्स (और समान डिवाइस) होते हैं।
ज़ेनो

1
स्वीकृत उत्तर के विपरीत, इस उत्तर में माप diffऔर के बीच किसी भी उल्लेखनीय अंतर को नहीं पहचानता है cmp
वेदी

जवाबों:


388

मेरा मानना ​​है cmpकि पहले बाइट अंतर पर रोक जाएगा:

cmp --silent $old $new || echo "files are different"

1
मैं केवल एक से अधिक कमांड कैसे जोड़ सकता हूं? मैं एक फाइल को कॉपी करके लूटना चाहता हूं।
फ़ीड

9
cmp -s $old $newभी काम करता है। -sके लिए कम है--silent
रोहर

7
गति बढ़ाने के रूप में, आपको सामग्री की तुलना करने से पहले फ़ाइल आकार की जांच करनी चाहिए। क्या किसी को पता है कि cmp ऐसा करता है?
बियोवुल्फ़न्यूड42

3
कई कमांड चलाने के लिए, आप कोष्ठक का उपयोग कर सकते हैं: cmp -s old new || {गूंज नहीं; प्रतिध्वनि; वही गूंज; }
अनफा

6
@ BeowulfNode42 हाँ, किसी भी सभ्य कार्यान्वयन cmpपहले फ़ाइल आकार की जाँच करेगा। यहाँ जीएनयू संस्करण है, यदि आप इसमें शामिल अतिरिक्त अनुकूलन देखना चाहते हैं: git.savannah.gnu.org/cgit/diffutils.git/tree/src/cmp.c
रयान ग्राहम

53

मुझे पसंद है @Alex Howansky ने इसके लिए 'cmp --silent' का इस्तेमाल किया है। लेकिन मुझे सकारात्मक और नकारात्मक प्रतिक्रिया दोनों की आवश्यकता है इसलिए मैं उपयोग करता हूं:

cmp --silent file1 file2 && echo '### SUCCESS: Files Are Identical! ###' || echo '### WARNING: Files Are Different! ###'

मैं इसे टर्मिनल में या एक ssh के साथ एक स्थिर फाइल के खिलाफ फाइल की जांच करने के लिए चला सकता हूं।


16
यदि आपकी echo successकमांड (या जो भी अन्य कमांड आपके स्थान पर रखी गई है) विफल हो जाती है, तो आपकी "नकारात्मक प्रतिक्रिया" कमांड चलाई जाएगी। आपको "यदि-तब-और-फिर" निर्माण का उपयोग करना चाहिए। उदाहरण के लिए, इस सरल उदाहरण की तरह ।
वाइल्डकार्ड

18

आपको दोनों फ़ाइलों की सामग्री का हैश क्यों नहीं मिला?

इस स्क्रिप्ट को आज़माएँ, इसे script.sh के लिए कॉल करें और फिर इसे निम्नानुसार चलाएँ: script.sh file1.txt file2.txt

#!/bin/bash

file1=`md5 $1`
file2=`md5 $2`

if [ "$file1" = "$file2" ]
then
    echo "Files have the same content"
else
    echo "Files have NOT the same content"
fi

2
@THISUSERNEEDSHELP ऐसा इसलिए है क्योंकि हैशिंग एल्गोरिदम एक से एक नहीं हैं । वे ऐसे डिज़ाइन किए गए हैं कि हैशिंग स्थान बड़ा है, और अलग-अलग इनपुट के पास अलग-अलग हैश का उत्पादन करने का एक उच्च मौका है। वास्तविकता यह है कि, हैश स्थान परिमित है, जबकि हैश के लिए संभावित फ़ाइलों की श्रेणी नहीं है - अंततः आपकी टक्कर होगी। क्रिप्टोलॉजी में इसे बर्थडे अटैक कहा जाता है ।
होगा

5
@ एह, यह प्रभावी रूप से काम करने की गारंटी है। यह काम नहीं कर रहे हैं, गणितीय रूप से, चारों ओर बोल रहे हैं 1/(2^511)। जब तक आप किसी के बारे में जानबूझकर चिंतित नहीं होते, तब तक टकराव पैदा करने की कोशिश करने वाले इस तरीके के विचार को गलत सकारात्मक बनाते हैं, वास्तव में एक गंभीर चिंता का विषय नहीं है। cmpहालाँकि यह अभी भी अधिक कुशल है, क्योंकि इसमें उस फ़ाइल को पूरी तरह से पढ़ना नहीं है जहाँ फाइलें मेल नहीं खाती हैं।
Ajedi32

12
ओपी ने सबसे तेजी से रास्ता पूछा ... पहली गैर-मिलान बिट (सीएमपी का उपयोग करके) की खोज तेज नहीं होगी (यदि वे मेल नहीं खाते हैं) पूरी फाइल को हैशिंग से, खासकर यदि फाइलें बड़ी हैं?
KoZm0kNoT

3
md5 सबसे अच्छा है अगर आप एक से कई तुलना कर रहे हैं। आप एक विशेषता के रूप में या प्रत्येक फ़ाइल के खिलाफ डेटाबेस में md5 हैश स्टोर कर सकते हैं। यदि कोई नई फ़ाइल दिखाई देती है और आपको यह देखना होगा कि क्या फ़ाइल फ़ाइल सिस्टम पर कहीं भी मौजूद है तो आप सभी नई फ़ाइल के हैश की गणना करते हैं और पिछले सभी के खिलाफ जांचते हैं। यकीन है कि Git एक बदलाव के दौरान फाइल में बदलाव के लिए हैशिंग का उपयोग करता है, लेकिन वे SHA1 का उपयोग करते हैं।
जिमहॉफ

3
@ BeowulfNode42 यही कारण है कि मैंने अपनी टिप्पणी "जब तक आप जानबूझकर किसी को टक्कर देने की कोशिश कर रहे हैं के बारे में चिंतित हैं"
Ajedi32

5

क्योंकि मैं चूसना और पर्याप्त प्रतिष्ठा अंक नहीं है मैं एक टिप्पणी के रूप में इस tidbit जोड़ नहीं सकते।

लेकिन, यदि आप cmpकमांड का उपयोग करने जा रहे हैं (और वर्बोज़ होने की आवश्यकता नहीं है / चाहते हैं) तो आप बस एक्ज़िट स्टेटस को पकड़ सकते हैं। प्रति cmpआदमी पृष्ठ:

यदि कोई फ़ाइल '-' या अनुपलब्ध है, तो मानक इनपुट पढ़ें। बाहर निकलने की स्थिति 0 है यदि इनपुट समान हैं, 1 यदि अलग है, तो 2 यदि परेशानी है।

तो, आप कुछ ऐसा कर सकते हैं:

STATUS="$(cmp --silent $FILE1 $FILE2; echo $?)"  # "$?" gives exit status for each comparison

if [[$STATUS -ne 0]]; then  # if status isn't equal to 0, then execute code
    DO A COMMAND ON $FILE1
else
    DO SOMETHING ELSE
fi

हाँ, लेकिन यह वास्तव में करने का अधिक जटिल तरीका है cmp --silent $FILE1 $FILE2 ; if [ "$?" == "1" ]; then echo "files differ"; fiजो बदले में करने का एक अधिक जटिल तरीका है cmp --silent $FILE1 $FILE2 || echo "files differ"क्योंकि आप सीधे अभिव्यक्ति में कमांड का उपयोग कर सकते हैं। यह स्थानापन्न करता है $?। परिणामस्वरूप कमांड के अस्तित्व की स्थिति की तुलना की जाएगी। और यही दूसरा जवाब देता है। btw। यदि कोई व्यक्ति संघर्ष कर रहा है --silent, तो वह हर जगह (बिजीबॉक्स) समर्थित नहीं है। उपयोग-s
पैपो

4

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

यहां कोई विकल्प नहीं है। इसलिए किसी समय में हैश या चेकसम बनाना पूरी फाइल को पढ़ने की आवश्यकता है। बड़ी फाइलें समय लेती हैं।

फ़ाइल मेटाडेटा पुनर्प्राप्ति एक बड़ी फ़ाइल पढ़ने की तुलना में बहुत तेज़ है।

तो, क्या कोई फ़ाइल मेटाडेटा है जिसे आप यह स्थापित करने के लिए उपयोग कर सकते हैं कि फाइलें अलग हैं? फाइल का आकार ? या फ़ाइल कमांड के परिणाम भी जो फ़ाइल के एक छोटे से हिस्से को पढ़ता है?

फ़ाइल आकार उदाहरण कोड टुकड़ा:

  ls -l $1 $2 | 
  awk 'NR==1{a=$5} NR==2{b=$5} 
       END{val=(a==b)?0 :1; exit( val) }'

[ $? -eq 0 ] && echo 'same' || echo 'different'  

यदि फ़ाइलें समान आकार की हैं, तो आप पूर्ण फ़ाइल रीड्स के साथ अटके हुए हैं।


1
ls -nयदि उपयोगकर्ता या समूह के नाम में व्हाट्सएप है तो मुद्दों से बचने के लिए उपयोग करें ।
त्रिकसे

2

Cksum कमांड का उपयोग करने का भी प्रयास करें:

chk1=`cksum <file1> | awk -F" " '{print $1}'`
chk2=`cksum <file2> | awk -F" " '{print $1}'`

if [ $chk1 -eq $chk2 ]
then
  echo "File is identical"
else
  echo "File is not identical"
fi

Cksum कमांड एक फाइल के बाइट काउंट को आउटपुट करेगा। देखें See आदमी कोसम ’।


2
मेरी पहली सोच भी यही थी। हालाँकि, हैश समझ में आता है यदि आपको एक ही फाइल की तुलना कई बार करनी है, क्योंकि हैश की गणना केवल एक बार की जाती है। यदि आप इसे केवल एक बार तुलना कर रहे हैं, तो md5वैसे भी पूरी फ़ाइल पढ़ता है, इसलिए cmp, पहले अंतर पर रोकना, तेजी से रास्ता होगा।
फ्रांसेस्को डोंडी

0

रास्पबेरी पाई 3 बी + (मैं एक ओवरले फ़ाइल सिस्टम का उपयोग कर रहा हूं, और समय-समय पर सिंक करने की आवश्यकता है) के साथ कुछ परीक्षण कर रहा हूं, मैंने डिफेक-सी और सीएमपी-एस के लिए अपनी खुद की तुलना की; ध्यान दें कि यह अंदर / देव / shm से एक लॉग है, इसलिए डिस्क एक्सेस स्पीड एक गैर-मुद्दा है:

[root@mypi shm]# dd if=/dev/urandom of=test.file bs=1M count=100 ; time diff -q test.file test.copy && echo diff true || echo diff false ; time cmp -s test.file test.copy && echo cmp true || echo cmp false ; cp -a test.file test.copy ; time diff -q test.file test.copy && echo diff true || echo diff false; time cmp -s test.file test.copy && echo cmp true || echo cmp false
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 6.2564 s, 16.8 MB/s
Files test.file and test.copy differ

real    0m0.008s
user    0m0.008s
sys     0m0.000s
diff false

real    0m0.009s
user    0m0.007s
sys     0m0.001s
cmp false
cp: overwrite âtest.copyâ? y

real    0m0.966s
user    0m0.447s
sys     0m0.518s
diff true

real    0m0.785s
user    0m0.211s
sys     0m0.573s
cmp true
[root@mypi shm]# pico /root/rwbscripts/utils/squish.sh

मैंने इसे एक-दो बार चलाया। cmp -s लगातार परीक्षण बॉक्स मैं उपयोग कर रहा था पर थोड़ा कम समय था। तो अगर आप दो फाइलों के बीच चीजों को करने के लिए cmp -s का उपयोग करना चाहते हैं ...।

identical (){
  echo "$1" and "$2" are the same.
  echo This is a function, you can put whatever you want in here.
}
different () {
  echo "$1" and "$2" are different.
  echo This is a function, you can put whatever you want in here, too.
}
cmp -s "$FILEA" "$FILEB" && identical "$FILEA" "$FILEB" || different "$FILEA" "$FILEB"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.