Unix में इसे सॉर्ट किए बिना डुप्लिकेट लाइनों को कैसे डिलीट करें?


136

क्या यूनिक्स में किसी फ़ाइल में डुप्लिकेट लाइनों को हटाने का एक तरीका है?

मैं इसे sort -uऔर uniqआदेशों के साथ कर सकता हूं , लेकिन मैं उपयोग करना चाहता हूं sedया awk। क्या यह संभव है?


11
यदि आप लगातार दोहराव का मतलब है तो uniqअकेले ही पर्याप्त है।
माइकल क्रेलिन - हैकर 12

और अन्यथा, मेरा मानना ​​है कि यह संभव है awk, लेकिन बड़ी फ़ाइलों पर उपभोग करने में काफी संसाधन होंगे।
माइकल क्रेलिन -

डुप्लिकेट्स stackoverflow.com/q/24324350 और stackoverflow.com/q/11532157 के दिलचस्प जवाब हैं जिन्हें आदर्श रूप से यहां पर माइग्रेट किया जाना चाहिए।
ट्रिपलए

जवाबों:


290
awk '!seen[$0]++' file.txt

seenएक साहचर्य-सरणी है जो Awk फ़ाइल की हर पंक्ति को पास करेगा। यदि कोई पंक्ति सरणी में नहीं है, तो seen[$0]गलत का मूल्यांकन करेगा। !एक तार्किक नहीं ऑपरेटर है और सच को गलत उलटने होगा। Awk उन रेखाओं को प्रिंट करेगा जहां अभिव्यक्ति सही का मूल्यांकन करती है। ++वेतन वृद्धि seenताकि seen[$0] == 1पहली बार के बाद एक लाइन पाया जाता है और उसके बाद seen[$0] == 2, और इतने पर।
Awk सब कुछ है, लेकिन मूल्यांकन करता है 0और ""सही करने के लिए (रिक्त स्ट्रिंग)। यदि एक डुप्लीकेट लाइन रखी जाती है seenतो !seen[$0]झूठी का मूल्यांकन करेगा और लाइन आउटपुट को नहीं लिखा जाएगा।


5
एक फ़ाइल में इसे बचाने के लिए हम यह कर सकते हैंawk '!seen[$0]++' merge_all.txt > output.txt
आकाश कांडपाल

5
यहां एक महत्वपूर्ण चेतावनी: यदि आपको कई फ़ाइलों के लिए ऐसा करने की आवश्यकता है, और आप कमांड के अंत में अधिक फ़ाइलों से निपटते हैं, या वाइल्डकार्ड का उपयोग करते हैं ... 'देखी गई' सरणी सभी फ़ाइलों से डुप्लिकेट लाइनों को भर देगी। यदि आप इसके बजाय प्रत्येक फ़ाइल का स्वतंत्र रूप से इलाज करना चाहते हैं, तो आपको कुछ करने की आवश्यकता होगीfor f in *.txt; do gawk -i inplace '!seen[$0]++' "$f"; done
निक K9

@ NickK9 कि कई फ़ाइलों में संचयी रूप से डी-डुबाना अपने आप में कमाल है। अच्छा टिप
sfscs

31

से http://sed.sourceforge.net/sed1line.txt : (कृपया मुझे यह कैसे काम करता मत पूछो ;-))

 # delete duplicate, consecutive lines from a file (emulates "uniq").
 # First line in a set of duplicate lines is kept, rest are deleted.
 sed '$!N; /^\(.*\)\n\1$/!P; D'

 # delete duplicate, nonconsecutive lines from a file. Beware not to
 # overflow the buffer size of the hold space, or else use GNU sed.
 sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'

geekery ;-) +1, लेकिन संसाधन की खपत अपरिहार्य है।
माइकल क्रेलिन -

3
! '$ एन; /^(.*)\n\1$/!P; D 'का अर्थ है "यदि आप अंतिम पंक्ति में नहीं हैं, तो किसी अन्य पंक्ति में पढ़ें। अब जो आपके पास है उसे देखें और यदि ISN'T सामान के बाद एक नई पंक्ति और फिर उसी सामान को फिर से प्रिंट करें, तो सामान को प्रिंट करें। अब हटाएं। सामान (न्यूलाइन तक)। ”
बीटा

2
'जी; s / \ N / && /; / ^ ([- ~] * \ n)। * \ n \ 1 / डी; s / \ N //; ज; P 'का अर्थ है, मोटे तौर पर, "पूरे होल्ड स्पेस को इस रेखा पर लागू करें, फिर यदि आप एक डुप्लिकेट की गई लाइन को पूरी चीज़ को फेंकते हुए देखते हैं, अन्यथा पूरे मेस को वापस होल्ड स्पेस में कॉपी करें और पहले भाग को प्रिंट करें (जो कि लाइन सिर्फ आप है पढ़ें। "
बीटा

क्या $!भाग आवश्यक है? sed 'N; /^\(.*\)\n\1$/!P; D'एक ही काम नहीं करता है? मैं एक उदाहरण के साथ नहीं आ सकता जहाँ दोनों मेरी मशीन पर अलग हैं (fwiw मैंने दोनों संस्करणों के साथ अंत में एक खाली लाइन की कोशिश की और वे दोनों ठीक थे)।
ईडी

1
लगभग 7 साल बाद और किसी ने भी जवाब नहीं दिया @ नाचिर ... <स्निफ> मुझे दुखी करता है। ;) वैसे भी, [ -~]0x20E (tilde) के 0x20 (स्थान) से ASCII वर्णों की एक श्रृंखला का प्रतिनिधित्व करता है। इन्हें मुद्रण योग्य ASCII वर्ण माना जाता है (लिंक किए गए पृष्ठ में 0x7F / delete भी है लेकिन यह सही नहीं लगता है)। यह किसी और के लिए ASCII या किसी का उपयोग न करने के लिए समाधान को तोड़ देता है, कहते हैं, टैब वर्ण .. अधिक पोर्टेबल [^\n]में एक पूरी बहुत अधिक वर्ण शामिल हैं ... सभी को छोड़कर, वास्तव में।
बी लेयर

14

Perl वन लाइनर @ जोनास के awk समाधान के समान:

perl -ne 'print if ! $x{$_}++' file

तुलना करने से पहले यह भिन्नता अनुगामी व्हाट्सएप को हटा देती है:

perl -lne 's/\s*$//; print if ! $x{$_}++' file

यह भिन्नता फ़ाइल में जगह संपादित करती है:

perl -i -ne 'print if ! $x{$_}++' file

यह भिन्नता फ़ाइल में जगह संपादित करती है, और एक बैकअप बनाती है file.bak

perl -i.bak -ne 'print if ! $x{$_}++' file

6

आंद्रे मिलर ने जो एक-लाइनर ऊपर पोस्ट किया है वह हाल के संस्करणों को छोड़कर काम करता है जब इनपुट फ़ाइल एक रिक्त रेखा और कोई वर्ण के साथ समाप्त होती है। मेरे मैक पर मेरा सीपीयू सिर्फ घूमता है।

अनंत लूप यदि अंतिम पंक्ति रिक्त है और कोई वर्ण नहीं है :

sed '$!N; /^\(.*\)\n\1$/!P; D'

लटका नहीं है, लेकिन आप अंतिम पंक्ति खो देते हैं

sed '$d;N; /^\(.*\)\n\1$/!P; D'

स्पष्टीकरण सेड के बहुत अंत में है :

GNU सेड मेंटेनर को लगा कि पोर्टेबिलिटी की समस्या होने के बावजूद
, N कमांड को प्रिंट करने (
डिलीट करने के बजाय ) में बदलने से पैटर्न स्पेस किसी के अंतर्विरोधों के साथ अधिक सुसंगत था
कि कैसे एक कमांड को "नेक्स्ट लाइन को जोड़ें" का व्यवहार करना चाहिए
परिवर्तन के पक्ष में एक और तथ्य यह था कि "{N; कमांड;}"
अंतिम पंक्ति हटा यदि फ़ाइल में विषम संख्या में लाइनें हों, लेकिन
फ़ाइल की समान संख्या होने पर अंतिम पंक्ति प्रिंट करें।

एन के पूर्व व्यवहार का उपयोग करने वाली लिपियों को परिवर्तित करने के लिए (
ईओएफ तक पहुंचने पर पैटर्न स्पेस को हटाते हुए) स्क्रिप्ट
को सीड के सभी संस्करणों के साथ संगत करने के लिए , एक अकेला "एन" बदलें। "$ d; एन;"


5

Vim (Vi संगत) का उपयोग कर एक वैकल्पिक तरीका :

फ़ाइल से डुप्लिकेट, लगातार लाइनें हटाएं:

vim -esu NONE +'g/\v^(.*)\n\1$/d' +wq

किसी फ़ाइल से डुप्लिकेट, नॉनकॉन्स्सेंट और नॉनमाइप लाइन हटाएं:

vim -esu NONE +'g/\v^(.+)$\_.{-}^\1$/d' +wq


4

पहला समाधान http://sed.sourceforge.net/sed1line.txt से भी है

$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr '$!N;/^(.*)\n\1$/!P;D'
1
2
3
4
5

मुख्य विचार यह है:

print ONLY once of each duplicate consecutive lines at its LAST appearance and use D command to implement LOOP.

बताते हैं:

  1. $!N;: यदि वर्तमान रेखा अंतिम रेखा नहीं है, Nतो अगली पंक्ति को पढ़ने के लिए कमांड का उपयोग करें pattern space
  2. /^(.*)\n\1$/!P: यदि धारा की सामग्री pattern spaceदो duplicate stringअलग हो जाती है \n, जिसका अर्थ है कि अगली पंक्ति sameवर्तमान रेखा के साथ है, तो हम इसे अपने मूल विचार के अनुसार मुद्रित नहीं कर सकते हैं; अन्यथा, जो मौजूदा लाइन का मतलब है अपने लगातार दो प्रतियों लाइनों के सभी के अंतिम उपस्थिति है, अब हम उपयोग कर सकते हैं Pआदेश वर्तमान में वर्ण मुद्रित करने के लिए pattern spaceutil \n( \nभी मुद्रित)।
  3. D: हम का उपयोग Dआदेश वर्तमान में वर्ण हटाने के लिए pattern spaceutil \n( \nभी नष्ट कर दिया), तो की सामग्री के pattern spaceअगली पंक्ति है।
  4. और Dकमांड sedइसके FIRSTकमांड पर कूदने के लिए मजबूर करेगा $!N, लेकिन फ़ाइल या मानक इनपुट स्ट्रीम से अगली पंक्ति को न पढ़ें।

दूसरा समाधान समझना आसान है (खुद से):

$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr 'p;:loop;$!N;s/^(.*)\n\1$/\1/;tloop;D'
1
2
3
4
5

मुख्य विचार यह है:

print ONLY once of each duplicate consecutive lines at its FIRST appearance and use : command & t command to implement LOOP.

बताते हैं:

  1. इनपुट स्ट्रीम या फ़ाइल से एक नई लाइन पढ़ें और इसे एक बार प्रिंट करें।
  2. नाम का उपयोग :loopकमांड सेट करें ।labelloop
  3. Nअगली पंक्ति को पढ़ने के लिए उपयोग करें pattern space
  4. s/^(.*)\n\1$/\1/वर्तमान लाइन को हटाने के लिए उपयोग करें यदि अगली पंक्ति वर्तमान लाइन के साथ समान है, तो हम कार्रवाई sकरने के लिए कमांड का उपयोग करते हैं delete
  5. यदि sकमांड को सफलतापूर्वक निष्पादित किया जाता है, तो नाम के लिए कूदने के लिए tloopकमांड बल sedका उपयोग करें , जो अगली पंक्तियों के लिए एक ही लूप का उपयोग करेगा लाइन की कोई डुप्लिकेट लगातार लाइनें नहीं हैं जो है ; अन्यथा, कमांड का उपयोग करें जो उसी के साथ है , और पहले कमांड पर कूदने के लिए बल है, जो कमांड है, वर्तमान की सामग्री अगली नई लाइन है।labellooplatest printedDdeletelatest-printed linesedppattern space

बिजीबॉक्स के साथ विंडोज पर एक ही कमांड:busybox echo -e "1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5" | busybox sed -nr "$!N;/^(.*)\n\1$/!P;D"
स्कैवेंजर

-1

यह awk का उपयोग करके प्राप्त किया जा सकता है
नीचे रेखा अद्वितीय मान प्रदर्शित करेगी

awk file_name | uniq

आप इन अद्वितीय मानों को एक नई फ़ाइल में आउटपुट कर सकते हैं

awk file_name | uniq > uniq_file_name

नई फ़ाइल uniq_file_name में केवल अनन्य मान होंगे, कोई डुप्लिकेट नहीं


-4
cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}'

Awk का उपयोग करके डुप्लिकेट लाइनों को हटाता है।


1
यह लाइनों के क्रम को परेशान करेगा।
विजय

1
20 जीबी टेक्स्ट फ़ाइल के बारे में क्या है? बहुत धीमा।
अलेक्जेंडर लुब्यागिन

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