किसी अन्य फ़ाइल A से फ़ाइल B पर दिखाई देने वाली पंक्तियों को कैसे निकालें?


160

मेरे पास एक बड़ी फ़ाइल ए (ईमेल से मिलकर), प्रत्येक मेल के लिए एक पंक्ति है। मेरे पास एक और फ़ाइल B भी है जिसमें मेल का एक और सेट है।

फाइल A से फाइल B में दिखाई देने वाले सभी पतों को हटाने के लिए मैं किस कमांड का उपयोग करूंगा।

इसलिए, यदि फ़ाइल में निहित है:

A
B
C

और फ़ाइल बी निहित:

B    
D
E

तब फ़ाइल A को साथ छोड़ दिया जाना चाहिए:

A
C

अब मुझे पता है कि यह एक ऐसा सवाल है जो शायद अधिक बार पूछा जा सकता है, लेकिन मुझे केवल एक ही आदेश ऑनलाइन मिला जिसने मुझे एक खराब डील-डौल के साथ त्रुटि दी।

कोई भी सहायताकाफी प्रशंसनीय होगी! कोई व्यक्ति निश्चित रूप से एक चतुर वन-लाइनर के साथ आएगा, लेकिन मैं शेल विशेषज्ञ नहीं हूं।



1
सबसे अधिक अगर यहां उत्तर छांटे गए फाइलों के लिए हैं, और सबसे स्पष्ट एक गायब है, जो निश्चित रूप से आपकी गलती नहीं है, लेकिन यह अन्य को आम तौर पर उपयोगी बनाता है।
ट्रिपल

जवाबों:


204

यदि फ़ाइलें क्रमबद्ध हैं (वे आपके उदाहरण में हैं):

comm -23 file1 file2

-23उन पंक्तियों को दबा देता है जो दोनों फ़ाइलों में हैं, या केवल फ़ाइल 2 में हैं। यदि फ़ाइलों को क्रमबद्ध नहीं किया गया है, तो उन्हें sortपहले से पाइप करें ...

मैन पेज यहाँ देखें


8
comm -23 file1 file2 > file3फाइल 2 में नहीं, फाइल 1 में आउटपुट सामग्री देगा। और फिर mv file3 file1अंत में फ़ाइल 1 में अनावश्यक सामग्री को साफ़ करेगा।
स्पेक्ट्रल

2
वैकल्पिक रूप से, उपयोग करें comm -23 file1 file2 | sponge file1। कोई सफाई की जरूरत है।
सोकोवई

मैन पेज लिंक मेरे लिए लोड नहीं हो रहा है - विकल्प: linux.die.net/man/1/comm
Felix Rabe

@Socowi स्पंज क्या है? मेरे पास अपने सिस्टम पर नहीं है। (मैकोस 10.13)
फेलिक्स राबे

@FelixRabe, ठीक है, यह थकाऊ है। आपके लिंक के साथ प्रतिस्थापित। धन्यवाद
ठेठ पॉल

85

grep -Fvxf <lines-to-remove> <all-lines>

  • गैर-सॉर्ट की गई फ़ाइलों पर काम करता है
  • आदेश बनाए रखता है
  • POSIX है

उदाहरण:

cat <<EOF > A
b
1
a
0
01
b
1
EOF

cat <<EOF > B
0
1
EOF

grep -Fvxf B A

आउटपुट:

b
a
01
b

स्पष्टीकरण:

  • -F: डिफ़ॉल्ट BRE के बजाय शाब्दिक तार का उपयोग करें
  • -x: केवल उन मैचों पर विचार करें जो पूरी रेखा से मेल खाते हों
  • -v: नॉन-मैचिंग प्रिंट करें
  • -f file: दी गई फ़ाइल से पैटर्न लें

यह विधि अन्य तरीकों की तुलना में पूर्व-सॉर्ट की गई फ़ाइलों पर धीमी है, क्योंकि यह अधिक सामान्य है। यदि गति भी मायने रखती है, तो देखें: एक फ़ाइल में लाइनों को खोजने का तेज़ तरीका जो दूसरे में नहीं है?

यहां इन-लाइन ऑपरेशन के लिए एक त्वरित बैश स्वचालन है:

remove-lines() (
  remove_lines="$1"
  all_lines="$2"
  tmp_file="$(mktemp)"
  grep -Fvxf "$remove_lines" "$all_lines" > "$tmp_file"
  mv "$tmp_file" "$all_lines"
)

गिटहब ऊपर

उपयोग:

remove-lines lines-to-remove remove-from-this-file

इसे भी देखें: /unix/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another


55

बचाव के लिए जाग!

इस समाधान को हल किए गए इनपुट की आवश्यकता नहीं है। आपको पहले fileB प्रदान करना होगा।

awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA

रिटर्न

A
C

यह कैसे काम करता है?

NR==FNR{a[$0];next} मुहावरा एक साहचर्य सरणी में पहली फ़ाइल को संग्रहीत करने के लिए है क्योंकि बाद में "परीक्षण" के लिए कुंजी होती है।

NR==FNR जाँच कर रहा है कि क्या हम पहली फ़ाइल को स्कैन कर रहे हैं, जहाँ वैश्विक लाइन काउंटर (NR) वर्तमान फ़ाइल लाइन काउंटर (FNR) के बराबर है।

a[$0] वर्तमान पंक्ति को साहचर्य सरणी में कुंजी के रूप में जोड़ता है, ध्यान दें कि यह एक सेट की तरह व्यवहार करता है, जहां कोई डुप्लिकेट मान (कुंजी) नहीं होगा

!($0 in a)अब हम अगली फ़ाइल inमें हैं, इसमें एक परीक्षण शामिल है, यहाँ यह जाँच कर रहा है कि क्या वर्तमान लाइन उस सेट में है जिसे हमने पहली फ़ाइल से पहले चरण में पॉपुलेट किया है, !स्थिति को उपेक्षित करता है। यहां क्या गायब है, यह कार्रवाई है, जो डिफ़ॉल्ट रूप से है {print}और आमतौर पर स्पष्ट रूप से नहीं लिखा जाता है।

ध्यान दें कि इसका उपयोग अब ब्लैकलिस्ट किए गए शब्दों को हटाने के लिए किया जा सकता है।

$ awk '...' badwords allwords > goodwords

एक मामूली बदलाव के साथ यह कई सूचियों को साफ कर सकता है और साफ किए गए संस्करण बना सकता है।

$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...

इस पर पूर्ण अंक। विंडोज में GnuWin32 में कमांड लाइन पर इसका इस्तेमाल करने के लिए सिंगल निबल्स को डबल कोट्स से बदलें। एक इलाज करता है। बहुत धन्यवाद।
टोबोबोब

यह काम करता है लेकिन मैं ए (एक नई लाइन के साथ) के रूप में फ़ाइलए में आउटपुट को रीडायरेक्ट करने में कैसे सक्षम होऊंगा
बिल्डर्स

मुझे लगता है कि आप मतलब है A\nC, पहले एक अस्थायी फ़ाइल को लिखें और मूल फ़ाइल को अधिलेखित करें... > tmp && mv tmp fileA
karakfa

इसमें मुझसे भी पूरे अंक मिले। 104,000 प्रविष्टियों के साथ फ़ाइल को संसाधित करने के लिए इस awk को 1 सेकंड का समय लगता है: +1:
मिशेल

स्क्रिप्ट में इसका उपयोग करते समय, पहले यह सुनिश्चित कर लें कि fileBखाली नहीं है (0 बाइट्स लंबी), क्योंकि यदि यह है, तो आपको अपेक्षित सामग्री के बजाय एक खाली परिणाम मिलेगा fileA। (कारण: FNR==NRउस पर लागू होगा fileA।)
पीटर Nowee


7

ऐसा आप तब तक कर सकते हैं जब तक कि आपकी फाइलें सॉर्ट न हो जाएं

diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a

--new-line-formatउन पंक्तियों के लिए है जो फ़ाइल b में हैं, लेकिन --old-..उन लाइनों के लिए नहीं हैं जो फ़ाइल में हैं, लेकिन b में नहीं उन --unchanged-..पंक्तियों के लिए है जो दोनों में हैं। %Lयह बनाता है ताकि लाइन बिल्कुल मुद्रित हो।

man diff

अधिक जानकारी के लिए


1
आप कहते हैं कि यह तब तक काम करेगा जब तक कि फाइलें छँट न जाएँ। यदि उन्हें हल किया जाए तो क्या समस्याएं आती हैं? यदि वे आंशिक रूप से हल किए जाते हैं तो क्या होगा?
कार्लोस मैकासेट

1
यह उस commकमांड के उपयोग के ऊपर दिए गए समाधान के जवाब में था । commफ़ाइलों को सॉर्ट करने की आवश्यकता होती है, इसलिए यदि उन्हें सॉर्ट किया जाता है तो आप उस समाधान का भी उपयोग कर सकते हैं। आप इस समाधान का उपयोग कर सकते हैं, भले ही फ़ाइल सॉर्ट की गई हो या नहीं
aec

7

@ करकफा के अच्छे जवाब का यह परिशोधन बहुत बड़ी फाइलों के लिए काफी तेज हो सकता है। उस उत्तर के रूप में, न तो फ़ाइल को क्रमबद्ध करने की आवश्यकता है, लेकिन गति का आश्वासन awk के साहचर्य सरणियों द्वारा दिया जाता है। केवल लुकअप फ़ाइल स्मृति में है।

यह सूत्रीकरण इस संभावना के लिए भी अनुमति देता है कि इनपुट फ़ाइल में केवल एक विशेष क्षेत्र ($ N) का उपयोग तुलना में किया जाना है।

# Print lines in the input unless the value in column $N
# appears in a lookup file, $LOOKUP;
# if $N is 0, then the entire line is used for comparison.

awk -v N=$N -v lookup="$LOOKUP" '
  BEGIN { while ( getline < lookup ) { dictionary[$0]=$0 } }
  !($N in dictionary) {print}'

(इस दृष्टिकोण का एक अन्य लाभ यह है कि तुलनात्मक मानदंड को संशोधित करना आसान है, उदाहरण के लिए सफेद स्थान को आगे और पीछे करना)


यह अन्य एक लाइनर की तुलना में कोने-केस क्रॉस प्लेटफॉर्म परिदृश्य में उपयोग करने के लिए कठिन है। हालांकि प्रदर्शन के प्रयास के लिए हैट
टोबोबोब

2

आप पायथन का उपयोग कर सकते हैं:

python -c '
lines_to_remove = set()
with open("file B", "r") as f:
    for line in f.readlines():
        lines_to_remove.add(line.strip())

with open("file A", "r") as f:
    for line in [line.strip() for line in f.readlines()]:
        if line not in lines_to_remove:
            print(line)
'

2

आप उपयोग कर सकते हैं - diff fileA fileB | grep "^>" | cut -c3- > fileA

यह उन फ़ाइलों के लिए काम करेगा, जिन्हें क्रमबद्ध नहीं किया गया है।


-1

दो फ़ाइलों के बीच की सामान्य लाइनों को हटाने के लिए आप grep का उपयोग कर सकते हैं, कमांड कर सकते हैं या कमांड में शामिल हो सकते हैं।

grep केवल छोटी फ़ाइलों के लिए काम करता है। -V के साथ -v का उपयोग करें।

grep -vf file2 file1 

यह फ़ाइल 1 से लाइनें प्रदर्शित करता है जो फ़ाइल 2 में किसी भी लाइन से मेल नहीं खाता है।

कॉम एक उपयोगिता कमांड है जो लेक्सिकली सॉर्ट की गई फ़ाइलों पर काम करता है। यह इनपुट के रूप में दो फाइलें लेता है और आउटपुट के रूप में तीन टेक्स्ट कॉलम बनाता है: केवल पहली फाइल में लाइनें; केवल दूसरी फ़ाइल में लाइनें; और दोनों फाइलों में लाइनें। आप अपने अनुसार -1, -2 या -3 विकल्प का उपयोग करके किसी भी कॉलम की प्रिंटिंग को दबा सकते हैं।

comm -1 -3 file2 file1

यह फ़ाइल 1 से लाइनें प्रदर्शित करता है जो फ़ाइल 2 में किसी भी लाइन से मेल नहीं खाता है।

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

join -v1 -v2 file1 file2

ये सभी पहले से ही अन्य उत्तरों में दिए गए थे। आपके grep को एक -F की आवश्यकता होती है, या आप अजीब परिणाम प्राप्त करेंगे जब रेखाएं regexps की तरह दिखेंगी
द आर्केटीपाल पॉल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.