दो फ़ाइलों को लाइन से तुलना करें और दूसरी फ़ाइल में अंतर उत्पन्न करें


121

मैं फ़ाइल 2 के साथ फाइल 1 की तुलना करना चाहता हूं और एक फाइल 3 उत्पन्न करता हूं जिसमें फाइल 1 में लाइनें शामिल हैं जो फाइल 2 में मौजूद नहीं हैं।


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

जवाबों:


216

diff (1) उत्तर नहीं है, लेकिन comm (1) है।

NAME
       comm - compare two sorted files line by line

SYNOPSIS
       comm [OPTION]... FILE1 FILE2

...

       -1     suppress lines unique to FILE1

       -2     suppress lines unique to FILE2

       -3     suppress lines that appear in both files

इसलिए

comm -2 -3 file1 file2 > file3

इनपुट फ़ाइलों को क्रमबद्ध किया जाना चाहिए। यदि वे नहीं हैं, तो उन्हें पहले क्रमबद्ध करें। यह एक अस्थायी फ़ाइल के साथ किया जा सकता है, या ...

comm -2 -3 <(sort file1) <(sort file2) > file3

बशर्ते कि आपका शेल प्रक्रिया प्रतिस्थापन (बैश करता है) का समर्थन करता है।


1
याद रखें कि दो फ़ाइलों को क्रमबद्ध किया जाना चाहिए और यह अद्वितीय है
andy

6
आप विकल्पों को एक साथ रख सकते हैं:comm -23
पाओलो एम

"क्रमबद्ध" का क्या अर्थ है? कि रेखाओं का क्रम समान है? तब शायद यह ज्यादातर उपयोग के मामलों के लिए ठीक है - जैसे कि, बैक-अप पुराने संस्करण के साथ तुलना करके क्या लाइनों को जोड़ा गया है। यदि नई जोड़ी गई लाइनें मौजूदा लाइनों के बीच नहीं हो सकती हैं, तो यह एक समस्या है।
ईगोर हंस

@EgorHans: यदि फ़ाइल में उदाहरण के लिए "3 \ n1 \ n3 \ n2 \ n" जैसे पूर्णांक वाली रेखाएँ हैं, तो सबसे पहले डुप्लिकेट के साथ आरोही या अवरोही क्रम में पुन: व्यवस्थित होना चाहिए जैसे "\ 1 \ n2 \ n3 \ n3" सटा हुआ। यह "सॉर्ट किया गया" है और दोनों फ़ाइलों को एक समान तरीके से सॉर्ट किया जाना चाहिए। जब नई फ़ाइल में नई लाइनें होती हैं, तो इससे कोई फर्क नहीं पड़ता कि क्या वे "मौजूदा लाइनों के बीच" हैं क्योंकि जिस तरह से वे नहीं हैं, उसके बाद वे क्रमबद्ध क्रम में हैं।
सोरइगल

48

यूनिक्स उपयोगिता diffवास्तव में इस उद्देश्य के लिए है।

$ diff -u file1 file2 > file3

विकल्पों के लिए मैनुअल और इंटरनेट देखें, विभिन्न आउटपुट प्रारूप, आदि।


8
यह अनुरोधित कार्य नहीं करता है; यह अतिरिक्त वर्णों का एक गुच्छा सम्मिलित करता है, यहां तक ​​कि अन्य उत्तरों में सुझाए गए कमांडलाइन स्विच के उपयोग के साथ भी।
जेनोकेन

20

इस पर विचार करें:
फ़ाइल a.txt:

abcd
efgh

फ़ाइल b.txt:

abcd

आप इसके साथ अंतर पा सकते हैं:

diff -a --suppress-common-lines -y a.txt b.txt

आउटपुट होगा:

efgh 

आप आउटपुट फ़ाइल (c.txt) में आउटपुट का उपयोग करके पुनर्निर्धारण कर सकते हैं:

diff -a --suppress-common-lines -y a.txt b.txt > c.txt

यह आपके प्रश्न का उत्तर देगा:

"" फ़ाइल 1 में वे पंक्तियाँ हैं जो फ़ाइल 2 में मौजूद नहीं हैं। "


2
इस उत्तर की दो सीमाएँ हैं: (1) यह केवल छोटी पंक्तियों (डिफ़ॉल्ट रूप से 80 वर्णों से कम) के लिए काम करता है, हालाँकि इसे संशोधित किया जा सकता है) और, अधिक महत्वपूर्ण, (2) यह प्रत्येक के अंत में एक "<" जोड़ता है। वह लाइन जिसे किसी अन्य प्रोग्राम (जैसे awk, sed) के साथ दूर ले जाना चाहिए।
सर्गुट

कई मामलों में, आप भी उपयोग करना चाहते हैं -d, जो diffसबसे छोटा संभव अंतर खोजने के लिए अपनी पूरी कोशिश करेंगे । -i, -E, -w, -Bऔर --suppress-blank-emptyभी उपयोगी कभी कभी हो सकता है, हालांकि हमेशा नहीं। यदि आप नहीं जानते कि आपके उपयोग के मामले में क्या फिट बैठता है, तो diff --helpपहले प्रयास करें (जो आम तौर पर एक अच्छा विचार है जब आपको नहीं पता कि एक कमांड क्या कर सकता है)।
ईगोर हंस

इसके अलावा, --line-format =% L का उपयोग करके, आप किसी भी अतिरिक्त वर्ण को उत्पन्न करने से अलग रहते हैं (कम से कम, मदद यह कहती है कि यह इस तरह काम करता है, फिर भी इसे आज़माने के बारे में)।
ईगोर हंस

इसके अलावा इस कम है और एक ही काम करता है लगता है stackoverflow.com/a/27667185/1179925
mrgloom

8

कभी-कभी diffआपकी आवश्यकता की उपयोगिता होती है, लेकिन कभी-कभी joinअधिक उपयुक्त होती है। फ़ाइलों को पूर्व-सॉर्ट किए जाने की आवश्यकता होती है या, यदि आप एक शेल का उपयोग कर रहे हैं जो प्रक्रिया प्रतिस्थापन जैसे बैश, ksh या zsh का समर्थन करता है, तो आप मक्खी पर सॉर्ट कर सकते हैं।

join -v 1 <(sort file1) <(sort file2)

इसके लिए आपको पदक मिलना चाहिए! यह वही था जो मैं पिछले 2 घंटों से देख रहा था
ज़तर्रा

7

प्रयत्न

sdiff file1 file2

यह ususally मेरे लिए ज्यादातर मामलों में बेहतर काम करता है। यदि आप लाइनों का क्रम महत्वपूर्ण नहीं है (उदाहरण के लिए कुछ पाठ विन्यास फाइल), तो आप फ़ाइलों को पहले क्रमबद्ध करना चाह सकते हैं।

उदाहरण के लिए,

sdiff -w 185 file1.cfg file2.cfg

1
अच्छी उपयोगिता! मैं प्यार करता हूँ कि यह विभेदक रेखाओं को कैसे चिह्नित करता है। कॉन्फ़िगरेशन की तुलना करना बहुत आसान बनाता है। यह एक साथ मिलकर एक घातक कॉम्बो (जैसे sdiff <(sort file1) <(sort file2)) है
jmagnusson

3

यदि आपको इसे कोर्यूटिल्स के साथ हल करने की आवश्यकता है तो स्वीकृत उत्तर अच्छा है:

comm -23 <(sort file1) <(sort file2) > file3

आप sd (स्ट्रीम डिफरेंट) का भी उपयोग कर सकते हैं , जिसके लिए न तो छँटाई की आवश्यकता होती है और न ही प्रतिस्थापन की प्रक्रिया होती है और अनंत धाराओं का समर्थन करता है, जैसे:

cat file1 | sd 'cat file2' > file3

शायद इस उदाहरण पर इतना लाभ नहीं है, लेकिन फिर भी इस पर विचार करें; कुछ मामलों में आप न तो उपयोग कर पाएंगे commऔर grep -Fन ही diff

यहाँ एक ब्लॉगपोस्ट है जो मैंने टर्मिनल पर अलग-अलग धाराओं के बारे में लिखा है, जो एसडी का परिचय देता है।


3

फिर भी, कोई grepसमाधान नहीं ?

  • लाइनें जो केवल फाइल 2 में मौजूद हैं:

    grep -Fxvf file1 file2 > file3
  • लाइनें जो केवल फ़ाइल 1 में मौजूद हैं:

    grep -Fxvf file2 file1 > file3
  • लाइनें जो दोनों फाइलों में मौजूद हैं:

    grep -Fxf file1 file2 > file3

2

कई जवाब पहले से ही, लेकिन उनमें से कोई भी सही IMHO नहीं है। थानाटोस का उत्तर प्रति पंक्ति में कुछ अतिरिक्त वर्ण छोड़ता है और सोरपाइगल के उत्तर के लिए फाइलों को क्रमबद्ध या पूर्व-छांटना पड़ता है, जो सभी परिस्थितियों में पर्याप्त नहीं हो सकता है।

मुझे लगता है कि लाइनों है कि विभिन्न और कुछ नहीं (बिना किसी अतिरिक्त वर्ण, कोई फिर से आदेश) कर रहे हैं होने का सबसे अच्छा तरीका है का एक संयोजन है diff, grepऔर awk(या समान)।

यदि लाइनों में कोई "<" नहीं है, तो एक छोटा लाइनर हो सकता है:

diff urls.txt* | grep "<" | sed 's/< //g'

लेकिन जो लाइनों से "<" (कम से कम, स्थान) के हर उदाहरण को हटा देगा, जो हमेशा ठीक नहीं होता है (जैसे स्रोत कोड)। सबसे सुरक्षित विकल्प awk का उपयोग करना है:

diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'

यह एक-लाइनर दोनों फाइलों को अलग करता है, फिर एड-स्टाइल आउटपुट के अंतर को फ़िल्टर करता है, और फिर "<" को हटाता है। यह तब भी काम करता है, जब लाइनों में कुछ "<" स्वयं हों।


1
कॉम को (नए संस्करणों में?) छंटाई की आवश्यकता नहीं है - बस --nocheck- ऑर्डर का उपयोग करें। मैं इसे बहुत उपयोग करते हैं जब सीएलआई से सीएसवी में हेरफेर करता है
ak5

2

मुझे आश्चर्य है कि किसी ने भी साइड-बाय-साइड आउटपुट का उल्लेख नहीं किया diff -yहै , उदाहरण के लिए:

diff -y file1 file2 > file3

और file3(विभिन्न पंक्तियों के |मध्य में एक प्रतीक है):

same     same
diff_1 | diff_2

1

डिफ यूटिलिटी का उपयोग करें और आउटपुट में <के साथ शुरू होने वाली केवल लाइनों को निकालें


0
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt

मैंने इस धागे में लगभग सभी उत्तरों की कोशिश की, लेकिन कोई भी पूरा नहीं हुआ। ऊपर कुछ ट्रेल्स के बाद मेरे लिए काम किया। अंतर आपको अंतर देगा लेकिन कुछ अवांछित विशेष चरस के साथ। जहाँ आप वास्तविक अंतर लाइनें '>' से शुरू करते हैं। तो अगले चरण पर है grep के साथ लाइनों शुरू होता है '>' और साथ ही हटाने के द्वारा पीछा किया sed


1
यह विचार अच्छा नहीं है। आपको शुरू होने वाली लाइनों को भी संशोधित करना होगा <। यदि आप इनपुट फ़ाइलों के क्रम को स्वैप करते हैं तो आप इसे देखेंगे। यहां तक ​​कि अगर आपने ऐसा किया है तो आप grepअधिक सेड का उपयोग करके छोड़ना चाहेंगे : `a1 a2 a1 | sed '/> / s ///' `यह अभी भी लाइन युक्त >या <सही स्थिति में टूट सकता है और अभी भी लाइन नंबर का वर्णन करने वाली अतिरिक्त लाइनें छोड़ देता है। यदि आप इस तरीके को आजमाना चाहते हैं तो बेहतर तरीका होगा diff -C0 a1 a2 | sed -ne '/^[+-] /s/^..//p':।
21

0

आप diffनिम्न आउटपुट स्वरूपण के साथ उपयोग कर सकते हैं :

diff --old-line-format='' --unchanged-line-format='' file1 file2

--old-line-format=''अगर फ़ाइल 2 में लाइन की तुलना अलग थी, तो फाइल 1 के लिए आउटपुट को अक्षम करें।
--unchanged-line-format='', यदि आउटपुट समान थे, तो आउटपुट को अक्षम करें।

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