यूनिक्स कमांड दो फ़ाइलों में आम लाइनों को खोजने के लिए


179

मुझे यकीन है कि मुझे एक बार एक यूनिक्स कमांड मिला है जो दो या अधिक फाइलों से आम लाइनों को प्रिंट कर सकता है, क्या किसी को इसका नाम पता है? की तुलना में यह बहुत सरल था diff


5
इस सवाल का जवाब जरूरी नहीं है कि हर कोई क्या चाहता है, क्योंकि इसके commलिए सॉर्ट किए गए इनपुट फ़ाइलों की आवश्यकता होती है। यदि आप लाइन-बाय-लाइन आम चाहते हैं, तो यह बहुत अच्छा है। लेकिन अगर आप चाहते हैं कि मैं "एंटी-डिफरेंस" कहूं, commतो यह काम नहीं करेगा।
रॉबर्ट पी। गोल्डमैन

@ रोबर्ट.गोल्डमैन दो फाइलों के बीच आम पाने का एक तरीका है जब फ़ाइल 1 में आंशिक पैटर्न होता है pr-123-xy-45और फ़ाइल 2 में होता है ec11_orop_pr-123-xy-45.gz। मुझे फ़ाइल 3 युक्त चाहिएec11_orop_pr-123-xy-45.gz
चंदन चौधरी

इसके लिए टेक्स्ट-फाइल्स लाइन-बाय-लाइन
y2k-shubham

जवाबों:


216

आप जो आदेश मांग रहे हैं वह है comm। जैसे: -

comm -12 1.sorted.txt 2.sorted.txt

यहाँ:

-1 : दमन कॉलम 1 (1.sorted.txt के लिए अद्वितीय लाइनें)

-2 : दमन स्तंभ 2 (लाइनें 2.sorted.txt के लिए अद्वितीय)


27
विशिष्ट उपयोग: comm -12 1.sorted.txt 2.sorted.txt
फेडिर RYKHTIK

45
जबकि कॉम को छंटनी की गई फ़ाइलों की जरूरत है, आप दोनों फाइलों की आम लाइनों को प्राप्त करने के लिए grep -f file1 file2 ले सकते हैं।
फेरी

2
@ferdy (आपके उत्तर से मेरी टिप्पणी को दोहराते हुए, जैसा कि आपका अनिवार्य रूप से एक टिप्पणी के रूप में दोहराया गया उत्तर है) grepकुछ अजीब चीजें करता है जो आप उम्मीद नहीं कर सकते हैं। विशेष रूप से, सब कुछ 1.txtएक नियमित अभिव्यक्ति के रूप में व्याख्या की जाएगी न कि एक सादे स्ट्रिंग के रूप में। साथ ही, कोई भी खाली लाइन 1.txtसभी लाइनों से मेल खाएगी 2.txt। तो grepकेवल बहुत विशिष्ट स्थितियों में काम करेगा। आप कम से कम fgrep(या grep -f) का उपयोग करना चाहते हैं, लेकिन इस प्रक्रिया पर रिक्त-पंक्ति वाली बात शायद कहर बरपा रही है।
क्रिस्टोफर शुल्त्स

11
देखें Ferdy के जवाब नीचे और, क्रिस्टोफर शुल्ज़ की और उस पर मेरी टिप्पणी। टीएल; डीआर - उपयोग grep -F -x -f file1 file2
जोनाथन लेफलर

1
@ बापर्स: मैंने एक स्व-उत्तरित प्रश्नोत्तर प्रदान किया है कि commकमांड से आउटपुट को 3 अलग-अलग फाइलों में कैसे लाया जाए ? यहाँ आराम से फिट होने के लिए जवाब बहुत बड़ा था।
जोनाथन लेफ्लर 5

62

आसानी से लागू करने के लिए संचार के लिए आदेश अवर्गीकृत फ़ाइलें, बैश का उपयोग प्रक्रिया प्रतिस्थापन :

$ bash --version
GNU bash, version 3.2.51(1)-release
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat > abc
123
567
132
$ cat > def
132
777
321

तो फाइलें abc और def में एक लाइन आम होती है, एक "132" के साथ। अनसुलझी फाइलों पर कॉम का उपयोग करना :

$ comm abc def
123
    132
567
132
    777
    321
$ comm -12 abc def # No output! The common line is not found
$

अंतिम पंक्ति ने कोई आउटपुट नहीं दिया, सामान्य रेखा की खोज नहीं की गई थी।

अब क्रमबद्ध फ़ाइलों पर कॉम का उपयोग करें, फाइलों को प्रक्रिया प्रतिस्थापन के साथ क्रमबद्ध करें:

$ comm <( sort abc ) <( sort def )
123
            132
    321
567
    777
$ comm -12 <( sort abc ) <( sort def )
132

अब हमें 132 लाइन मिल गई!


2
तो ... sort abc > abc.sorted, sort dev > def.sortedऔर फिर comm -12 abc.sorted def.sorted?
निकाना रेक्लवैक्स

1
@NikanaReklawyks और फिर बाद में अस्थायी फ़ाइलों को हटाने और त्रुटि के मामले में सफाई का सामना करने के लिए याद रखें। कई परिदृश्यों में, प्रक्रिया प्रतिस्थापन भी बहुत तेज होगा क्योंकि आप डिस्क I / O से बच सकते हैं जब तक कि परिणाम मेमोरी में फिट हो जाते हैं।
ट्रिपलए

29

पर्ल वन-लाइनर के पूरक के लिए, यहाँ इसके awkसमकक्ष है:

awk 'NR==FNR{arr[$0];next} $0 in arr' file1 file2

यह file1सरणी में से सभी पंक्तियों को पढ़ेगा arr[], और फिर प्रत्येक पंक्ति की जांच करेगा file2यदि यह पहले से ही सरणी (यानी file1) के भीतर मौजूद है । जो लाइनें मिलती हैं उन्हें उसी क्रम में प्रिंट किया जाएगा जिसमें वे दिखाई देते हैं file2। ध्यान दें कि तुलना in arrपूरी पंक्ति file2को अनुक्रमणिका से सरणी तक ले जाती है, इसलिए यह केवल संपूर्ण रेखाओं पर सटीक मिलान रिपोर्ट करेगी।


2
यह सही जवाब है। दूसरों में से कोई भी आम तौर पर काम करने के लिए नहीं बनाया जा सकता है (मैंने perlलोगों की कोशिश नहीं की है, क्योंकि)। एक लाख धन्यवाद, सुश्री
एंटोनियो

1
सामान्य रेखाओं को प्रदर्शित करते समय ऑर्डर को संरक्षित करना कुछ मामलों में वास्तव में उपयोगी हो सकता है जो इसके कारण कॉम को बाहर कर देंगे।
टक्सायो

1
यदि कोई व्यक्ति एक निश्चित कॉलम के आधार पर एक ही काम करना चाहता है, लेकिन उसे पता नहीं है, तो बस $ 5 को कॉलम 5 के उदाहरण के लिए $ 5 से बदल दें, इसलिए आपको कॉलम 5 में समान शब्दों के साथ 2 फ़ाइलों में साझा की गई लाइनें मिलेंगी
फतिहसरिगॉल

24

शायद आपका मतलब है comm?

क्रमबद्ध फ़ाइलों FILE1 और FILE2 लाइन की तुलना लाइन द्वारा करें।

कोई विकल्प नहीं होने पर, तीन-स्तंभ आउटपुट का उत्पादन करें। कॉलम एक में FILE1 के लिए अद्वितीय लाइनें हैं, कॉलम दो में FILE2 के लिए अद्वितीय लाइनें हैं, और कॉलम तीन में दोनों फ़ाइलों के लिए आम लाइनें हैं।

इन सूचनाओं को खोजने में रहस्य सूचना पृष्ठ हैं। जीएनयू कार्यक्रमों के लिए, वे अपने मैन-पेज की तुलना में अधिक विस्तृत हैं। कोशिश करो info coreutilsऔर यह आपको सभी छोटे उपयोगी बर्तनों को सूचीबद्ध करेगा।


19

जबकि

grep -v -f 1.txt 2.txt > 3.txt

आपको दो फ़ाइलों का अंतर देता है (2.txt में क्या है और 1.txt में नहीं), आप आसानी से कर सकते हैं a

grep -f 1.txt 2.txt > 3.txt

सभी आम लाइनों को इकट्ठा करने के लिए, जो आपकी समस्या का आसान समाधान प्रदान करें। यदि आपने फ़ाइलों को सॉर्ट किया है, तो आपको commफिर भी लेना चाहिए । सादर!


2
grepकुछ अजीब चीजें करता है जो आप उम्मीद नहीं कर सकते हैं। विशेष रूप से, सब कुछ 1.txtएक नियमित अभिव्यक्ति के रूप में व्याख्या की जाएगी न कि एक सादे स्ट्रिंग के रूप में। साथ ही, कोई भी खाली लाइन 1.txtसभी लाइनों से मेल खाएगी 2.txt। तो यह केवल बहुत विशिष्ट स्थितियों में काम करेगा।
क्रिस्टोफर शुल्त्स

13
@ChristopherSchultz: POSIX grepनोटेशन का उपयोग करके बेहतर तरीके से काम करने के लिए इस उत्तर को अपग्रेड करना संभव है, जो कि grepअधिकांश आधुनिक यूनिक्स वेरिएंट पर पाए गए द्वारा समर्थित हैं । नियमित अभिव्यक्ति को दबाने के लिए -F(या उपयोग fgrep) जोड़ें । -xकेवल संपूर्ण रेखाओं को मिलाने के लिए (सटीक रूप से) जोड़ें ।
जोनाथन लेफलर

हमें commसॉर्ट की गई फ़ाइलों के लिए क्यों लेना चाहिए ?
यूलसीज़ बीएन

2
@UlysseBN commमनमाने ढंग से बड़ी फ़ाइलों के साथ काम कर सकता है जब तक कि उन्हें सॉर्ट किया जाता है क्योंकि यह केवल मेमोरी में तीन लाइनें रखने की आवश्यकता होती है (मुझे अनुमान है कि जीएनयू को commयह भी पता होगा कि अगर लाइनें वास्तव में लंबी हैं तो सिर्फ एक उपसर्ग रखना होगा)। grepसमाधान स्मृति में सभी खोज भाव रखने की जरूरत है।
ट्रिपलए

9

यदि दो फ़ाइलों को अभी तक सॉर्ट नहीं किया गया है, तो आप उपयोग कर सकते हैं:

comm -12 <(sort a.txt) <(sort b.txt)

और यह काम करेंगे, त्रुटि संदेश से बचने comm: file 2 is not in sorted order जब कर comm -12 a.txt b.txt


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

मैंने इस उत्तर को @JonathanLeffler भी नहीं देखा क्योंकि यह भाग उत्तर के बहुत ही अंत में था, पहले उत्तर के अन्य तत्वों के साथ मिलाया गया था। जबकि दूसरा उत्तर अधिक सटीक है, मेरा लाभ मुझे लगता है कि किसी ऐसे व्यक्ति के लिए जो त्वरित समाधान चाहता है, उसके पास पढ़ने के लिए केवल 2 लाइनें होंगी। कभी-कभी हम विस्तृत उत्तर की तलाश में होते हैं और कभी-कभी हम जल्दी में होते हैं और जल्दी से तैयार होने वाला पेस्ट पेस्ट ठीक होता है।
बसज

इसके अलावा, मैं क्रेडिट / प्रतिनिधि की परवाह नहीं करता, मैंने इस उद्देश्य के लिए पोस्ट नहीं किया।
बसज

1
यह भी ध्यान दें कि प्रक्रिया प्रतिस्थापन सिंटैक्स <(command)POSIX शेल के लिए पोर्टेबल नहीं है, हालांकि यह बैश और कुछ अन्य में काम करता है।
ट्रिपलए

8
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2

इससे बेहतर काम कर रहा है commआदेश के रूप में यह की प्रत्येक पंक्ति खोज file1में file2जहां commकेवल तुलना लाइन अगर होगा nमें file1है लाइन के बराबर nमें file2
तेरीइहिना

1
@terihhina: नहीं; commकेवल फाइल एन में लाइन एन के साथ फाइल एन में लाइन एन की तुलना न करें। यह पूरी तरह से किसी भी फ़ाइल में डाली गई लाइनों की एक श्रृंखला को अच्छी तरह से प्रबंधित कर सकता है (जो अन्य फ़ाइल से लाइनों की एक श्रृंखला को हटाने के बराबर है, निश्चित रूप से)। यह केवल इनपुट के लिए क्रमबद्ध क्रम में होना चाहिए।
जोनाथन लेफ़लर

commयदि कोई आदेश रखना चाहता है तो उत्तर से बेहतर है । awkजवाब से बेहतर अगर कोई डुप्लिकेट नहीं चाहता है।
tuxayo

एक स्पष्टीकरण यहाँ है: stackoverflow.com/questions/17552789/…
क्रिस Koknat


3

लिनक्स के सीमित संस्करण पर (जैसे कि QNAP (nas) मैं काम कर रहा था):

  • कॉम मौजूद नहीं था
  • grep -f file1 file2@ChristopherSchultz द्वारा कहा गया कुछ समस्याओं का कारण हो सकता है और उपयोग करना grep -F -f file1 file2वास्तव में धीमा था (5 मिनट से अधिक - इसे समाप्त नहीं किया - 20 एमबी से अधिक फ़ाइलों पर नीचे की विधि के साथ 2-3 सेकंड से अधिक)

तो मैंने यह किया :

sort file1 > file1.sorted
sort file2 > file2.sorted

diff file1.sorted file2.sorted | grep "<" | sed 's/^< *//' > files.diff
diff file1.sorted files.diff | grep "<" | sed 's/^< *//' > files.same.sorted

यदि files.same.sortedमूल आदेश की तुलना में समान क्रम में रहा हो, तो फ़ाइल 1 की तुलना में उसी क्रम के लिए यह पंक्ति जोड़ें:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file1 > files.same

या, file2 से समान क्रम के लिए:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file2 > files.same

2

बस संदर्भ के लिए अगर कोई अभी भी कई फ़ाइलों के लिए यह करने के लिए देख रहा है, तो कई फ़ाइलों में मिलान लाइनों को खोजने के लिए जुड़ा हुआ उत्तर देखें


इन दो उत्तरों ( ans1 और ans2 ) को मिलाकर , मुझे लगता है कि आप उन फ़ाइलों को प्राप्त कर सकते हैं जिन्हें आप बिना फाइलों को छांटे कर सकते हैं:

#!/bin/bash
ans="matching_lines"

for file1 in *
do 
    for file2 in *
        do 
            if  [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then
                echo "Comparing: $file1 $file2 ..." >> $ans
                perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans
            fi
         done 
done

बस इसे सहेजें, इसे निष्पादन अधिकार ( chmod +x compareFiles.sh) दें और इसे चलाएं। यह वर्तमान कार्यशील निर्देशिका में मौजूद सभी फ़ाइलों को ले जाएगा और परिणाम में "मिलान_लाइन्स" फ़ाइल को छोड़कर सभी बनाम बनाम की तुलना करेगा।

बेहतर होने वाली चीजें:

  • निर्देशिका छोड़ें
  • सभी फाइलों की तुलना दो बार करने से बचें (file1 vs file2 and file2 vs file1)।
  • हो सकता है कि मिलान स्ट्रिंग के आगे लाइन नंबर जोड़ें

-2
rm file3.txt

cat file1.out | while read line1
do
        cat file2.out | while read line2
        do
                if [[ $line1 == $line2 ]]; then
                        echo $line1 >>file3.out
                fi
        done
done

यह करना चाहिए।


1
rm -f file3.txtयदि आप फ़ाइल को हटाने जा रहे हैं तो आपको संभवतः उपयोग करना चाहिए ; यदि फ़ाइल मौजूद नहीं है तो किसी भी त्रुटि की सूचना नहीं दी जाएगी। OTOH, यह आवश्यक नहीं होगा यदि आपकी स्क्रिप्ट केवल मानक आउटपुट पर गूँजती हो, स्क्रिप्ट के उपयोगकर्ता को यह चुनने देती है कि आउटपुट कहाँ जाना चाहिए। अंततः, आप निश्चित फ़ाइल नामों ( और ) के बजाय संभवतः ( $1और $2कमांड लाइन तर्क) का उपयोग करना चाहते हैं । वह एल्गोरिथम छोड़ देता है: यह धीमा होने वाला है। यह प्रत्येक पंक्ति के लिए एक बार पढ़ने वाला है । यदि फ़ाइलें बड़ी हैं (तो कई किलोबाइट कहते हैं) यह धीमा होगा। file1.outfile2.outfile2.outfile1.out
जोनाथन लेफ़लर

हालांकि यह नाममात्र काम कर सकता है यदि आपके पास इनपुट हैं जिसमें कोई शेल मेटाचैकर नहीं है (संकेत: देखें कि आपको शेलचेक.नेट से क्या चेतावनियाँ मिलती हैं ), यह भोली दृष्टिकोण बहुत अक्षम है। एक उपकरण grep -Fजो एक फ़ाइल को मेमोरी में पढ़ता है और फिर दोनों इनपुट फ़ाइलों पर बार-बार लूपिंग से बचा जाता है।
त्रिवेणी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.