उन्हें हटाए बिना किसी फ़ाइल में डुप्लिकेट लाइनों की पहचान करें?


11

मेरे पास प्रविष्टियों की एक लंबी सूची के साथ एक पाठ फ़ाइल के रूप में मेरे संदर्भ हैं और प्रत्येक में दो (या अधिक) फ़ील्ड हैं।

पहला कॉलम संदर्भ का url है; दूसरा कॉलम शीर्षक है जो प्रवेश कैसे किया गया था इसके आधार पर थोड़ा भिन्न हो सकता है। तीसरे क्षेत्र के लिए भी जो मौजूद हो भी सकता है और नहीं भी।

मैं उन प्रविष्टियों को पहचानना चाहता हूं लेकिन उन प्रविष्टियों को नहीं हटाता जिनमें पहला क्षेत्र (संदर्भ url) समरूप है। मैं इसके बारे में जानता हूं, sort -k1,1 -uलेकिन यह स्वचालित रूप से (गैर-अंतःक्रियात्मक) सभी को हटा देगा, लेकिन पहली हिट। वहाँ एक तरीका है बस मुझे पता है तो मैं जो बनाए रखने के लिए चुन सकते हैं?

एक ही प्रथम फ़ील्ड ( http://unix.stackexchange.com/questions/49569/) के तीन रेखाओं के नीचे के अर्क में , मैं पंक्ति 2 रखना चाहूंगा क्योंकि इसमें अतिरिक्त टैग (सॉर्ट, CLI) हैं और # 1 और # 3 लाइनों को हटा दें:

http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

क्या ऐसे "डुप्लिकेट" की पहचान करने में मदद करने के लिए एक कार्यक्रम है? फिर, मैं व्यक्तिगत रूप से # 1 और # 3 लाइनों को हटाकर सफाई कर सकता हूं?


मैं आपके उदाहरण को काफी नहीं समझता ... क्या आप इनपुट और अपेक्षित आउटपुट का अधिक सरलीकृत संस्करण दे सकते हैं?
ओली

कृपया देखें कि क्या यह अभी स्पष्ट है?
डीके बोस

जवाबों:


9

यदि मुझे आपका प्रश्न समझ में आता है, तो मुझे लगता है कि आपको कुछ इस तरह की आवश्यकता है:

for dup in $(sort -k1,1 -u file.txt | cut -d' ' -f1); do grep -n -- "$dup" file.txt; done

या:

for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n -- "$dup" file.txt; done

file.txtआपकी फ़ाइल में आपके बारे में डेटा रखने वाली रुचि कहाँ है।

आउटपुट में आप उन लाइनों और लाइनों की संख्या देखेंगे जहां पहला क्षेत्र दो या अधिक बार पाया जाता है।


3
धन्यवाद: cut -d " " -f1 file.txt | uniq -dमुझे भी अच्छा आउटपुट देता है।
डीके बोस

@DKBose संभवतः अधिक संभावनाएं हैं, लेकिन मैं उपयोग करना चाहता था और आपकी आज्ञा भी।
रादु राईडेनू

धन्यवाद। दूसरा कमांड मुझे पसंद है। आप पहले को हटा सकते हैं। और अगर आप उस कोड की व्याख्या करते हैं जो अच्छा भी होगा :)
डीके बोस

10

यह एक शास्त्रीय समस्या है जिसे uniqकमांड से हल किया जा सकता है । uniqडुप्लिकेट का पता लगा सकते लगातार (लाइनों और निकालें डुप्लिकेट -u, --unique) या डुप्लिकेट केवल रखने के ( -d, --repeated)।

चूंकि डुप्लिकेट लाइनों का ऑर्डर करना आपके लिए महत्वपूर्ण नहीं है, इसलिए आपको इसे पहले सॉर्ट करना चाहिए। इसके बाद uniqयूनिक लाइन प्रिंट करने के लिए उपयोग करें:

sort yourfile.txt | uniq -u

एक -c( --count) विकल्प भी है जो -dविकल्प के लिए डुप्लिकेट की संख्या को प्रिंट करता है । uniqविवरण के लिए मैनुअल पेज देखें।


यदि आप वास्तव में पहले क्षेत्र के बाद के हिस्सों की परवाह नहीं करते हैं, तो आप डुप्लिकेट कुंजियों को खोजने के लिए निम्न कमांड का उपयोग कर सकते हैं और इसके लिए प्रत्येक पंक्ति संख्या को प्रिंट कर सकते हैं (दूसरे | sort -nको लाइन द्वारा क्रमबद्ध आउटपुट के लिए संलग्न करें ):

 cut -d ' ' -f1 .bash_history | nl | sort -k2 | uniq -s8 -D

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

यहां एक AWK स्क्रिप्ट है (इसे सेव करें script.awk) जो आपकी टेक्स्ट फाइल को इनपुट के रूप में लेती है और सभी डुप्लिकेट लाइनों को प्रिंट करती है ताकि आप यह तय कर सकें कि किसको डिलीट करना है। ( awk -f script.awk yourfile.txt)

#!/usr/bin/awk -f
{
    # Store the line ($0) grouped per URL ($1) with line number (NR) as key
    lines[$1][NR] = $0;
}
END {
    for (url in lines) {
        # find lines that have the URL occur multiple times
        if (length(lines[url]) > 1) {
            for (lineno in lines[url]) {
                # Print duplicate line for decision purposes
                print lines[url][lineno];
                # Alternative: print line number and line
                #print lineno, lines[url][lineno];
            }
        }
    }
}

मुझे लगता है कि यह वही है जो मैं चाहता हूं, लेकिन मुझे `-f, --स्काइप-फील्ड्स = एन के विपरीत की आवश्यकता है (पहले एन क्षेत्रों की तुलना करने से बचें)। दूसरे शब्दों में, मैं केवल पहला क्षेत्र चाहता हूं, जो कि विचार किया जाना चाहिए।
डीके बोस

@DKBose एक निश्चित संख्या के वर्णों तक सीमित करने के लिए एक -w( --check-chars) विकल्प है, लेकिन आपके उदाहरण को देखते हुए, आपके पास चर पहले क्षेत्र हैं। चूंकि uniqफ़ील्ड चयन का समर्थन नहीं करता है, इसलिए आपको वर्कअराउंड का उपयोग करना होगा। मैं एक AWK उदाहरण शामिल करूंगा क्योंकि यह आसान है।
लेकेन्स्टाइन

हां, मैं अभी देख रहा था -wलेकिन पहले क्षेत्र की लंबाई परिवर्तनशील है :(
डीके बोस

@DKBose कृपया नवीनतम एडिट
लेकेनस्टाइन

1
पर सिंटेक्स त्रुटि या निकट}: मैं हो रही है awk: script.awk: पर या निकट [awk सिंटेक्स त्रुटि: script.awk: लाइन 4 लाइन 10: पर या निकट [awk सिंटेक्स त्रुटि: script.awk: लाइन 18
DK बोस

2

अगर मैं इसे सही ढंग से पढ़ता हूं, तो आपको बस कुछ चाहिए

awk '{print $1}' file | sort | uniq -c | 
    while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done

यह उस रेखा की संख्या का प्रिंट आउट लेगा जिसमें द्वैध और रेखा स्वयं है। उदाहरण के लिए, इस फ़ाइल का उपयोग कर:

foo bar baz
http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
bar foo baz
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
baz foo bar
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

यह इस उत्पादन का उत्पादन करेगा:

2:http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
4:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
6:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

केवल पंक्ति की संख्या मुद्रित करने के लिए, आप कर सकते हैं

awk '{print $1}' file | sort | uniq -c | 
 while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 1

और केवल लाइन प्रिंट करने के लिए:

awk '{print $1}' file | sort | uniq -c | 
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 2-

स्पष्टीकरण:

awkस्क्रिप्ट सिर्फ प्रिंट 1 अंतरिक्ष फ़ाइल के क्षेत्र अलग कर दिया। $NNth फ़ील्ड प्रिंट करने के लिए उपयोग करें । sortइसे uniq -cक्रमबद्ध करें और प्रत्येक पंक्ति की घटनाओं को गिनें।

इसके बाद whileलूप को पास किया जाता है, जो कि आवृत्तियों की संख्या $numऔर रेखा को बचाता है $dupeऔर यदि $numएक से अधिक है (इसलिए इसे कम से कम एक बार दोहराया गया है) तो वह उस पंक्ति के लिए फ़ाइल को खोज लेगा, -nलाइन नंबर को प्रिंट करने के लिए। --बताता है grepकि क्या इस प्रकार एक कमांड लाइन विकल्प, जब के लिए उपयोगी नहीं है $dupeके साथ शुरू कर सकते हैं -


1

कोई शक नहीं कि सूची में सबसे अधिक क्रिया एक है, शायद कम हो सकती है:

#!/usr/bin/python3
import collections
file = "file.txt"

def find_duplicates(file):
    with open(file, "r") as sourcefile:
        data = sourcefile.readlines()
    splitlines = [
        (index, data[index].split("  ")) for index in range(0, len(data))
        ]
    lineheaders = [item[1][0] for item in splitlines]
    dups = [x for x, y in collections.Counter(lineheaders).items() if y > 1]
    dupsdata = []
    for item in dups:
        occurrences = [
            splitlines_item[0] for splitlines_item in splitlines\
                       if splitlines_item[1][0] == item
            ]
        corresponding_lines = [
            "["+str(index)+"] "+data[index] for index in occurrences
            ]
        dupsdata.append((occurrences, corresponding_lines))

    # printing output   
    print("found duplicates:\n"+"-"*17)
    for index in range(0, len(dups)):
        print(dups[index], dupsdata[index][0])
        lines = [item for item in dupsdata[index][1]]
        for line in lines:
            print(line, end = "")


find_duplicates(file)

टेक्स्टफाइल पर देता है जैसे:

monkey  banana
dog  bone
monkey  banana peanut
cat  mice
dog  cowmeat

एक आउटपुट की तरह:

found duplicates:
-----------------
dog [1, 4]
[1] dog  bone
[4] dog  cowmeat
monkey [0, 2]
[0] monkey  banana
[2] monkey  banana peanut

एक बार जब आप लाइनों को हटाने के लिए:

removelist = [2,1]

def remove_duplicates(file, removelist):
    removelist = sorted(removelist, reverse=True)
    with open(file, "r") as sourcefile:
        data = sourcefile.readlines()
    for index in removelist:
        data.pop(index)
    with open(file, "wt") as sourcefile:
        for line in data:
            sourcefile.write(line)

remove_duplicates(file, removelist)

0

निम्न क्रमबद्ध देखें file.txt:

addons.mozilla.org/en-US/firefox/addon/click-to-play-per-element/ ::: C2P per-element
addons.mozilla.org/en-us/firefox/addon/prospector-oneLiner/ ::: OneLiner
askubuntu.com/q/21033 ::: What is the difference between gksudo and gksu?
askubuntu.com/q/21148 ::: openoffice calc sheet tabs (also askubuntu.com/q/138623)
askubuntu.com/q/50540 ::: What is Ubuntu's Definition of a "Registered Application"?
askubuntu.com/q/53762 ::: How to use lm-sensors?
askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors
stackoverflow.com/q/4594319 ::: bash - shell replace cr\lf by comma
stackoverflow.com/q/4594319 ::: shell replace cr\lf by comma
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence - Ubuntu Wiki
www.youtube.com/watch?v=1olY5Qzmbk8 ::: Create new mime types in Ubuntu
www.youtube.com/watch?v=2hu9JrdSXB8 ::: Change mouse cursor
www.youtube.com/watch?v=Yxfa2fXJ1Wc ::: Mouse cursor size

क्योंकि सूची छोटी है, मैं देख सकता हूं (छांटने के बाद) कि डुप्लिकेट के तीन सेट हैं।

फिर, उदाहरण के लिए, मैं रख सकता हूं:

askubuntu.com/q/53762 ::: How to use lm-sensors?

बजाय

askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors

लेकिन लंबी सूची के लिए यह मुश्किल होगा। दो उत्तरों के आधार पर एक सुझाव uniqऔर दूसरा सुझाव देने के आधार पर cut, मुझे लगता है कि यह कमांड मुझे वह आउटपुट देता है जो मैं चाहूंगा:

$ cut -d " " -f1 file.txt | uniq -d
askubuntu.com/q/53762
stackoverflow.com/q/4594319
wiki.ubuntu.com/ClipboardPersistence
$

मैंने अपने उत्तर को दूसरे संस्करण के साथ अद्यतन किया है cut। यदि आप डी-डुप्लिकेटिंग काम कर रहे हैं, तो लाइन नंबर बहुत मददगार हो सकते हैं। सभी डुप्लिकेट को प्रिंट करने के लिए, के -Dबजाय विकल्प का उपयोग करें -d
लेकेनस्टाइन

मुझे लगता है कि आप बेहतर उपयोग करते हैं: for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n $dup file.txt; doneजैसा कि मेरे उत्तर में है। यह आपको आपकी रुचि के बारे में बेहतर पूर्वावलोकन देगा।
रादु राईडेनु

0

उसका यह है कि मैंने इसे कैसे हल किया:

file_with_duplicates:

1,a,c
2,a,d
3,a,e <--duplicate
4,a,t
5,b,k <--duplicate
6,b,l
7,b,s
8,b,j
1,b,l
3,a,d <--duplicate
5,b,l <--duplicate

कॉलम 1 और 2 के आधार पर छांटे और काटे गए फ़ाइल:

sort -t',' -k1,1 -k2,2 -u file_with_duplicates

केवल कॉलम 1 और 2 द्वारा छांटी गई फ़ाइल:

sort -t',' -k1,1 -k2,2 file_with_duplicates

केवल अंतर दिखाएं:

diff <(sort -t',' -k1,1 -k2,2 -u file_with_duplicates) <(sort -t',' -k1,1 -k2,2 file_with_duplicates)

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