मेरे पास एक फाइल है f1
:
line1
line2
line3
line4
..
..
मैं उन सभी लाइनों को हटाना चाहता हूं जो किसी अन्य फ़ाइल में हैं f2
:
line2
line8
..
..
मैंने कुछ के साथ कोशिश की cat
और sed
, जो मेरे इरादे के करीब भी नहीं था। मैं यह कैसे कर सकता हूँ?
मेरे पास एक फाइल है f1
:
line1
line2
line3
line4
..
..
मैं उन सभी लाइनों को हटाना चाहता हूं जो किसी अन्य फ़ाइल में हैं f2
:
line2
line8
..
..
मैंने कुछ के साथ कोशिश की cat
और sed
, जो मेरे इरादे के करीब भी नहीं था। मैं यह कैसे कर सकता हूँ?
जवाबों:
grep -v -x -f f2 f1
चाल चलनी चाहिए।
स्पष्टीकरण:
-v
गैर-मिलान लाइनों का चयन करने के लिए-x
केवल पूरी रेखाओं का मिलान करने के लिए-f f2
से पैटर्न प्राप्त करने के लिए f2
एक के बजाय का उपयोग कर सकते grep -F
या fgrep
मैच के लिए तय तार से f2
बजाय पैटर्न (मामले में आप नहीं बल्कि में लाइनों के उपचार की तुलना में एक "जो आप देखते है, तो क्या आप प्राप्त" तरीके से लाइनों को हटाने चाहते f2
regex पैटर्न के रूप में)।
grep
। यदि यह f2
खोज शुरू करने से पहले ठीक से ठीक हो जाए तो खोज में केवल O (n) समय लगेगा।
इसके बजाय कॉम की कोशिश करें (f1 और f2 मानकर "पहले से ही हल किया हुआ है")
comm -2 -3 f1 f2
comm
है कि समाधान है सवाल यह नहीं दर्शाता है कि लाइनें f1
comm
comm -2 -3 <(sort f1) <(sort f2)
उन फ़ाइलों को बाहर करने के लिए जो बहुत बड़ी नहीं हैं, आप AWK की सहयोगी सरणियों का उपयोग कर सकते हैं।
awk 'NR == FNR { list[tolower($0)]=1; next } { if (! list[tolower($0)]) print }' exclude-these.txt from-this.txt
आउटपुट "से- it.txt" फ़ाइल के समान क्रम में होगा। tolower()
अगर आपको लगता है कि जरूरत समारोह, यह केस-संवेदी बना देता है।
एल्गोरिथम की जटिलता शायद ओ (n) (अपवर्जित-इन टेक्स्ट आकार) + O (n) (from-this.txt आकार) होगी
exclude-these.txt
खाली होने पर यह विफल रहता है (अर्थात कोई आउटपुट नहीं देता है) । @ जोना-क्रिस्टोफर- sahnwaldt का उत्तर इस मामले में नीचे दिया गया है। आप कई फ़ाइलों को भी निर्दिष्ट कर सकते हैं जैसेawk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 done.out failed.out f=2 all-files.out
डेनिस विलियमसन के उत्तर के समान (ज्यादातर वाक्यात्मक परिवर्तन, उदाहरण के लिए NR == FNR
चाल के बजाय फ़ाइल संख्या स्पष्ट रूप से सेट करना ):
awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 exclude-these.txt f=2 from-this.txt
एक्सेस करने r[$0]
से उस लाइन के लिए एंट्री हो जाती है, मान सेट करने की आवश्यकता नहीं होती।
यह मानकर कि awk निरंतर खोज और (औसतन) निरंतर अद्यतन समय के साथ एक हैश तालिका का उपयोग करता है, इस की समय जटिलता O (n + m) होगी, जहाँ n और m फाइलों की लंबाई हैं। मेरे मामले में, n ~ 25 मिलियन और m ~ 14000 था। जाग समाधान हल की तुलना में बहुत तेज था, और मैंने मूल आदेश को रखना भी पसंद किया।
f
क्लीयर लगता है NR == FNR
, लेकिन यह स्वाद की बात है। हैश में असाइनमेंट इतना तेज होना चाहिए कि दो संस्करणों के बीच कोई औसत गति अंतर न हो। मुझे लगता है कि मैं जटिलता के बारे में गलत था - यदि लुकअप स्थिर है, तो अपडेट निरंतर (औसत रूप से) होना चाहिए। मुझे नहीं पता कि मुझे लगा कि अपडेट लॉगरिदमिक होगा। मैं अपना उत्तर संपादित करूँगा।
awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 empty.file done.out failed.out f=2 all-files.out
। जबकि अन्य awk
समाधान खाली बहिष्कृत फ़ाइल के साथ विफल रहता है और केवल एक ही ले सकता है।
अगर आपके पास रूबी (1.9+) है
#!/usr/bin/env ruby
b=File.read("file2").split
open("file1").each do |x|
x.chomp!
puts x if !b.include?(x)
end
जिसमें O (N ^ 2) जटिलता है। यदि आप प्रदर्शन के बारे में परवाह करना चाहते हैं, तो यहां एक और संस्करण है
b=File.read("file2").split
a=File.read("file1").split
(a-b).each {|x| puts x}
जो घटाव को प्रभावित करने के लिए हैश का उपयोग करता है, इसलिए जटिलता O (n) (a) का आकार + O (n) (b का आकार) है
यहाँ एक छोटा बेंचमार्क है, जो उपयोक्ता 576875 के सौजन्य से है, लेकिन उपरोक्त में से 100K लाइनों के साथ:
$ for i in $(seq 1 100000); do echo "$i"; done|sort --random-sort > file1
$ for i in $(seq 1 2 100000); do echo "$i"; done|sort --random-sort > file2
$ time ruby test.rb > ruby.test
real 0m0.639s
user 0m0.554s
sys 0m0.021s
$time sort file1 file2|uniq -u > sort.test
real 0m2.311s
user 0m1.959s
sys 0m0.040s
$ diff <(sort -n ruby.test) <(sort -n sort.test)
$
diff
यह दिखाने के लिए इस्तेमाल किया गया था कि उत्पन्न 2 फ़ाइलों के बीच कोई अंतर नहीं है।
विभिन्न अन्य उत्तरों के बीच कुछ समय की तुलना:
$ for n in {1..10000}; do echo $RANDOM; done > f1
$ for n in {1..10000}; do echo $RANDOM; done > f2
$ time comm -23 <(sort f1) <(sort f2) > /dev/null
real 0m0.019s
user 0m0.023s
sys 0m0.012s
$ time ruby -e 'puts File.readlines("f1") - File.readlines("f2")' > /dev/null
real 0m0.026s
user 0m0.018s
sys 0m0.007s
$ time grep -xvf f2 f1 > /dev/null
real 0m43.197s
user 0m43.155s
sys 0m0.040s
sort f1 f2 | uniq -u
सममितीय अंतर भी नहीं है, क्योंकि यह उन पंक्तियों को हटा देता है जो या तो फ़ाइल में कई बार दिखाई देती हैं।
स्टड के साथ कॉम का भी उपयोग किया जा सकता है और यहां तार:
echo $'a\nb' | comm -23 <(sort) <(sort <<< $'c\nb') # a
SQLite शेल के लिए उपयुक्त नौकरी लगती है:
create table file1(line text);
create index if1 on file1(line ASC);
create table file2(line text);
create index if2 on file2(line ASC);
-- comment: if you have | in your files then specify “ .separator ××any_improbable_string×× ”
.import 'file1.txt' file1
.import 'file2.txt' file2
.output result.txt
select * from file2 where line not in (select line from file1);
.q
'प्रोग्रामिंग' का जवाब नहीं है, लेकिन यहाँ एक त्वरित और गंदा समाधान है: बस http://www.listdiff.com/compare-2-lists-difference-tool पर जाएं ।
जाहिर है बड़ी फ़ाइलों के लिए काम नहीं करेगा, लेकिन यह मेरे लिए चाल चली। कुछ नोट: