दो बड़ी फ़ाइलों का अंतर


14

मेरे पास "test1.csv" है और इसमें शामिल है

200,400,600,800
100,300,500,700
50,25,125,310

और test2.csv और इसमें सम्‍मिलित है

100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5

अभी

diff test2.csv test1.csv > result.csv

से अलग है

diff test1.csv test2.csv > result.csv

मुझे नहीं पता कि सही क्रम कौन सा है, लेकिन मुझे कुछ और चाहिए, ऊपर के दोनों कमांड कुछ इस तरह आउटपुट करेंगे

2 > 100,4,2,1,7
   3 2,3c3,5
   4 < 100,300,500,700
   5 < 50,25,125,310
   6 \ No newline at end of file
   7 ---
   8 > 21,22,23,24,25
   9 > 50,25,125,310

मैं केवल अंतर को आउटपुट करना चाहता हूं, इस प्रकार results.csv को इस तरह दिखना चाहिए

100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

मैंने कोशिश की diff -qऔर diff -sउन्होंने चाल नहीं चली। आदेश मायने नहीं रखता, जो मायने रखता है कि मैं केवल अंतर देखना चाहता हूं, न> और न ही <या रिक्त स्थान।

grep -FvF छोटे फ़ाइलों पर चाल बड़े लोगों पर नहीं किया

पहली फ़ाइल में 5 मिलियन से अधिक लाइनें हैं, दूसरी फ़ाइल में 1300 हैं।

so results.csv का परिणाम ~ 4,998,700 लाइनों में होना चाहिए

मैंने भी कोशिश की grep -F -x -v -f जो काम नहीं किया।



1
@ मुझे आपका लिंक दिखाई दिया और मैं एक पुराना सदस्य हूं, इसलिए मुझे पता है कि मैं नियमों के प्रति लापरवाह था, क्षमा करें :) इसे संपादित कर रहा था, और मैंने एक पॉपअप देखा कि पोस्ट को संपादित किया गया था, इसलिए आपने मेरे लिए काम किया और मैं आभारी सर।
लिंगोब

50,25,125,310दोनों फ़ाइल के लिए आम है..आपको अपने वांछित आउटपुट से हटाने की जरूरत है ..
heemayl

क्या आदेश को संरक्षित किया जाना चाहिए?
कोस

1
सूचना के साथ आप क्या करना चाहते हैं, इस पर निर्भर करता है, अंतर, IMO, पैच बनाने के लिए है। किसी भी दर पर, मुझे अब आपके सर्वोत्तम उपकरण, फ़र्क, grep, awk, या perl पर यकीन है।
पैंथर

जवाबों:


20

के लिए एक नौकरी की तरह लगता है comm:

$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
    100,4,2,1,7
    21,22,23,24,25
    50,25,700,5

जैसा कि समझाया गया है man comm:

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

तो, -3इसका मतलब है कि केवल एक फ़ाइल के लिए अद्वितीय लाइनें मुद्रित की जाएंगी। हालाँकि, वे किस फ़ाइल के अनुसार इंडेंटेड हैं। टैब को हटाने के लिए, उपयोग करें:

$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

इस मामले में, आपको वास्तव में फ़ाइलों को सॉर्ट करने की आवश्यकता नहीं है और आप ऊपर दिए गए को सरल बना सकते हैं:

comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv

तुम 200,[...]हुह लाइन के बाद रिक्त स्थान से मूर्ख नहीं किया गया है? :)
कोस

@ नहीं, मैंने पहले फाइलों से ट्रेलिंग स्पेस को हटा दिया। मैंने मान लिया कि ओपी की फाइलें वास्तव में उनके पास नहीं हैं।
टेराडॉन

6

प्रक्रिया प्रतिस्थापन के grepसाथ प्रयोग करना bash:

$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

आउटपुट को बचाने के लिए results.csv:

cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
  • <()है bashप्रक्रिया प्रतिस्थापन पैटर्न

  • grep -vFf test2.csv test1.csv केवल अद्वितीय लाइनों मिल जाएगा test1.csv

  • grep -vFf test1.csv test2.csv केवल अद्वितीय लाइनों मिल जाएगा test2.csv

  • अंत में हम परिणाम को संक्षेप में रखते हैं cat

या जैसा कि ओली ने सुझाव दिया , आप कमांड ग्रुपिंग का भी उपयोग कर सकते हैं:

$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

या बस एक के बाद एक चलाएं, क्योंकि वे दोनों STDOUT पर लिख रहे हैं कि वे अंततः जुड़ जाएंगे:

$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

1
catदो पुनर्निर्देशित आदेश क्यों ? सिर्फ एक ही नहीं तो दूसरा क्यों? grep ... ; grep ...या { grep ... ; grep ... ; }यदि आप सामूहिक आउटपुट के साथ कुछ करना चाहते थे।
ओली

@ ओली धन्यवाद..एक महान विचार..मैंने ऐसा नहीं सोचा ..
heemayl

4

यदि पंक्तियों का क्रम प्रासंगिक नहीं है, तो उपयोग करें awkया perl:

awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv

grepसामान्य रेखाएँ प्राप्त करने और उन्हें फ़िल्टर करने के लिए उपयोग करें :

grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv

आंतरिक grep को आम लाइनें मिलती हैं, फिर बाहरी grep उन पंक्तियों को ढूंढता है जो इन आम लाइनों से मेल नहीं खाती हैं।


आपकी awk कमांड बस फिर से लागू होती है sort | uniq -u, जो एक फाइल डुप्लिकेट लाइनों में होने पर गलत उत्तर देती है। Grep के लिए, मैं "आंतरिक" / "बाहरी" कहूंगा, "आंतरिक" / "बाहरी" नहीं।
पीटर कॉर्डेस

@PeterCordes हाँ, यह करता है और आप कौन हैं यह कहना है कि गलत परिणाम है?
मुरु

इस अर्थ में गलत है कि यह उस कोने के मामले में वास्तव में पूछा गया सवाल नहीं है। यह वही हो सकता है जो कोई चाहता है, लेकिन आपको इस बात का अंतर बताना चाहिए कि आपका awkप्रिंट क्या होगा comm -3और diffउत्तर क्या प्रिंट होंगे।
पीटर कॉर्डेस

@PeterCordes फिर, आप कौन हैं? जब तक ओपी कहता है कि वे चाहते हैं, मुझे परवाह नहीं है अगर आउटपुट इससे अलग है comm -3। मुझे कोई कारण नहीं दिख रहा है कि मैं क्यों समझाऊं। यदि आप एक नोट में संपादित करना चाहते हैं, तो स्वतंत्र महसूस करें।
मुरु

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

4

के --*-line-format=...विकल्पों का उपयोग करेंdiff

आप बता सकते diffहैं कि आपको क्या चाहिए - नीचे बताया गया है:

diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' f1.txt f2.txt

printfसंख्या के प्रारूप के समान, बहुत विस्तृत तरीके से आउटपुट के आउटपुट को निर्दिष्ट करना संभव है ।

पहली फ़ाइल से पंक्तियों को test1.csv"पुरानी" लाइनें कहा जाता है, और दूसरी से लाइनें test2.csv"नई" लाइनें हैं। जब समझ में आता हैdiff है कि फ़ाइल में क्या बदला है यह देखने के लिए उपयोग किया जाता है।

हमें जिन विकल्पों की आवश्यकता है वे हैं "पुरानी" लाइनों, "नई" लाइनों और "अपरिवर्तित" लाइनों के लिए प्रारूप सेट करने के लिए।
हमें जिन स्वरूपों की आवश्यकता है वे बहुत सरल हैं:
परिवर्तित लाइनों के लिए, नए और पुराने, हम केवल लाइनों के पाठ का उत्पादन करना चाहते हैं। %Lरेखा पाठ के लिए प्रारूप प्रतीक है।
अपरिवर्तित लाइनों के लिए, हम कुछ भी नहीं दिखाना चाहते हैं।

इसके साथ, हम --old-line-format='%L'आपके उदाहरण डेटा का उपयोग करके, जैसे विकल्प लिख सकते हैं और इसे एक साथ रख सकते हैं:

$ diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' test1.csv test2.csv
100,4,2,1,7
100,300,500,700
21,22,23,24,25
50,25,700,5


प्रदर्शन पर नोट्स

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

diffबड़ी फ़ाइलों के साथ उपयोग करने के लिए एक अनुकूलन विकल्प है --speed-large-files:। यह फ़ाइल संरचना के बारे में मान्यताओं का उपयोग करता है, इसलिए यह स्पष्ट नहीं है कि यह आपके मामले में मदद करता है, लेकिन यह कोशिश करने के लायक है।

प्रारूप विकल्पों का वर्णन man diffनीचे दिया गया है --LTYPE-line-format=LFMT


3

चूंकि आदेश को संरक्षित करने की आवश्यकता नहीं है, बस:

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csv: विलय और प्रकार test1.csvऔरtest2.csv
  • uniq -u: केवल उन पंक्तियों को प्रिंट करता है जिनकी कोई डुप्लिकेट नहीं है

यदि एक फ़ाइल में दो बार एक पंक्ति होती है, तो वह काम नहीं करती है, जो दूसरी फ़ाइल में दिखाई नहीं देती है। दोनों घटनाएँ एक diffपरिणाम के रूप में होंगी ।
वोल्कर सिएगल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.