क्या स्तंभ द्वारा 'यूनीक' करने का कोई तरीका है?


195

मेरे पास इस तरह एक .csv फ़ाइल है:

stack2@example.com,2009-11-27 01:05:47.893000000,example.net,127.0.0.1
overflow@example.com,2009-11-27 00:58:29.793000000,example.net,255.255.255.0
overflow@example.com,2009-11-27 00:58:29.646465785,example.net,256.255.255.0
...

मुझे फ़ाइल से डुप्लिकेट ई-मेल (पूरी लाइन) को हटाना होगा (यानी overflow@example.comउपरोक्त उदाहरण में दी गई लाइनों में से एक)। मैं uniqकेवल फ़ील्ड 1 (अल्पविराम द्वारा अलग) पर कैसे उपयोग करूं ? के अनुसार man, uniqकॉलम के लिए विकल्प नहीं है।

मैं कुछ के साथ की कोशिश की, sort | uniqलेकिन यह काम नहीं करता है।

जवाबों:


326
sort -u -t, -k1,1 file
  • -u अद्वितीय के लिए
  • -t, तो अल्पविराम सीमांकक है
  • -k1,1 प्रमुख क्षेत्र 1 के लिए

परीक्षा परिणाम:

overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 

3
यदि कॉलम में स्वयं कॉमा (उद्धरण सहित)
user775187

13
आपको 1, -k1,1 की आवश्यकता क्यों है? क्यों नहीं -k1?
हेल्लो_थेरे_ंडी

18
@hello_there_andy: यह मैनुअल ( man sort) में समझाया गया है । यह स्टार्ट और स्टॉप पोजीशन के लिए खड़ा है।
सेरानो

3
@CarlSmotricz: मैं यह परीक्षण किया है और इस बात की पुष्टि क्या sortहै मैनपेज कहते हैं: " -u, --unique के साथ -c, सख्त आदेश देने के लिए जाँच; बिना -c, उत्पादन एक समान रन का केवल पहला ।" तो, यह वास्तव में "छँटाई से पहले डुप्लिकेट की पहली घटना है।"
गेरीमिया

2
यह लाइनों के क्रम को भी बदलता है, है ना?
राकच

103
awk -F"," '!_[$1]++' file
  • -F फ़ील्ड विभाजक सेट करता है।
  • $1 पहला क्षेत्र है।
  • _[val]valहैश _(एक नियमित चर) में दिखता है ।
  • ++ वेतन वृद्धि, और पुराना मान लौटाते हैं।
  • ! तार्किक लौटाता है।
  • अंत में एक अंतर्निहित प्रिंट है।

4
यह दृष्टिकोण दो बार की तुलना में तेजी से गुना है
21

9
मूल क्रम में लाइनों को रखने का यह अतिरिक्त लाभ भी है!
AffluentOwl

8
यदि आपको पहले के बजाय अंतिम uniq की आवश्यकता है तो यह awk स्क्रिप्ट मदद करेगा:awk -F',' '{ x[$1]=$0 } END { for (i in x) print x[i] }' file
Sukima

3
@ महज डिक्शनरी इंडेक्स में और फील्ड जोड़ते हैं! उदाहरण के लिए, !_[$1][$2]++पहले दो क्षेत्रों के आधार पर छाँटे जा सकते हैं। मेरे awk-fu मजबूत क्षेत्रों की एक श्रृंखला पर अद्वितीय करने के लिए सक्षम होने के लिए पर्याप्त है, हालांकि नहीं है। :(
सोहम चौधरी

1
प्रतिभाशाली! यह विकल्प उत्तर से बेहतर है क्योंकि यह लाइनों का क्रम रखता है
rachachach

16

कई कॉलम पर विचार करने के लिए।

कॉलम 1 और कॉलम 3 के आधार पर विशिष्ट सूची को क्रमबद्ध करें और दें:

sort -u -t : -k 1,1 -k 3,3 test.txt
  • -t : बृहदान्त्र विभाजक है
  • -k 1,1 -k 3,3 कॉलम 1 और कॉलम 3 पर आधारित है

8

या यदि आप यूनीक का उपयोग करना चाहते हैं:

<mycvs.cvs tr -s ',' ' ' | awk '{print $3" "$2" "$1}' | uniq -c -f2

देता है:

1 01:05:47.893000000 2009-11-27 tack2@domain.com
2 00:58:29.793000000 2009-11-27 overflow@domain2.com
1

5
मैं एक संभावित सरलीकरण इंगित करना चाहता हूं: आप डंप कर सकते हैं cat! Tr में पाइप करने के बजाय, बस tr को फ़ाइल का उपयोग करके पढ़ने दें <। पाइपिंग के माध्यम catसे एक आम अनावश्यक जटिलता है जो नौसिखियों द्वारा उपयोग की जाती है। बड़ी मात्रा में डेटा के लिए प्रदर्शन प्रभाव होना चाहिए था।
कार्ल स्मोत्रिकज

4
जानकार अच्छा लगा। धन्यवाद! (निश्चित रूप से यह समझ में आता है, "बिल्ली" और "आलसीपन" की सोच;))
कार्स्टन सी।

खेतों के उत्क्रमण को सरल बनाया जा सकता है rev
हेलीके वालिंगा

5

यदि आप डुप्लिकेट के अंतिम एक को बनाए रखना चाहते हैं जो आप उपयोग कर सकते हैं

 tac a.csv | sort -u -t, -r -k1,1 |tac

जो मेरी आवश्यकता थी

यहाँ

tac फ़ाइल लाइन को लाइन से उल्टा करेगा


1

यहाँ एक बहुत ही अच्छा तरीका है।

पहले सामग्री को ऐसे स्वरूपित करें कि विशिष्टता के लिए स्तंभ की तुलना एक निश्चित चौड़ाई हो। ऐसा करने का एक तरीका फ़ील्ड / कॉलम चौड़ाई निर्दिष्ट ("% 15s") के साथ awk प्रिंटफ़ का उपयोग करना है।

अब uniq के -f और -w विकल्पों का उपयोग पूर्ववर्ती क्षेत्रों / स्तंभों को छोड़ने और तुलना चौड़ाई (कॉलम (s) चौड़ाई) को निर्दिष्ट करने के लिए किया जा सकता है।

यहाँ तीन उदाहरण हैं।

पहले उदाहरण में ...

1) अस्थायी रूप से क्षेत्र के अधिकतम चौड़ाई की तुलना में ब्याज की कॉलम को एक निश्चित चौड़ाई से अधिक या उसके बराबर बनाते हैं।

2) पूर्व स्तंभों को छोड़ने के लिए -f uniq विकल्प का उपयोग करें, और -w uniq विकल्प का उपयोग चौड़ाई को tmp_fixed_width पर सीमित करने के लिए करें।

3) "रिस्टोर" करने के लिए कॉलम से ट्रेलिंग स्पेस निकालें यह चौड़ाई है (यह मानते हुए कि पहले से कोई ट्रेलिंग स्पेस नहीं थे)।

printf "%s" "$str" \
| awk '{ tmp_fixed_width=15; uniq_col=8; w=tmp_fixed_width-length($uniq_col); for (i=0;i<w;i++) { $uniq_col=$uniq_col" "}; printf "%s\n", $0 }' \
| uniq -f 7 -w 15 \
| awk '{ uniq_col=8; gsub(/ */, "", $uniq_col); printf "%s\n", $0 }'

दूसरे उदाहरण में ...

एक नया यूनीक कॉलम बनाएं 1. यूनीक फ़िल्टर लागू होने के बाद इसे हटा दें।

printf "%s" "$str" \
| awk '{ uniq_col_1=4; printf "%15s %s\n", uniq_col_1, $0 }' \
| uniq -f 0 -w 15 \
| awk '{ $1=""; gsub(/^ */, "", $0); printf "%s\n", $0 }'

तीसरा उदाहरण दूसरे के समान है, लेकिन कई कॉलम के लिए है।

printf "%s" "$str" \
| awk '{ uniq_col_1=4; uniq_col_2=8; printf "%5s %15s %s\n", uniq_col_1, uniq_col_2, $0 }' \
| uniq -f 0 -w 5 \
| uniq -f 1 -w 15 \
| awk '{ $1=$2=""; gsub(/^ */, "", $0); printf "%s\n", $0 }'

-3

अच्छी तरह से, जाग के साथ कॉलम को अलग करने की तुलना में सरल है, अगर आपको किसी दिए गए फ़ाइल के लिए एक निश्चित मूल्य के साथ सब कुछ हटाने की आवश्यकता है, तो बस grep -v क्यों न करें:

दूसरी जगह लाइन में "col2" मान के साथ सब कुछ हटाने के लिए: col1, col2, col3, col4

grep -v ',col2,' file > file_minus_offending_lines

यदि यह पर्याप्त रूप से अच्छा नहीं है, क्योंकि कुछ पंक्तियाँ संभवतः अलग-अलग कॉलम में मिलान मूल्य दिखाने से अनुचित रूप से छीन सकती हैं, तो आप ऐसा कुछ कर सकते हैं:

आक्रामक कॉलम को अलग करने के लिए awk: जैसे

awk -F, '{print $2 "|" $line}'

-F सेट फ़ील्ड को ",", $ 2 का अर्थ है स्तंभ 2, इसके बाद कुछ कस्टम सीमांकक और फिर संपूर्ण पंक्ति। फिर आप उन पंक्तियों को हटाकर फ़िल्टर कर सकते हैं जो आक्रामक मान से शुरू होती हैं:

 awk -F, '{print $2 "|" $line}' | grep -v ^BAD_VALUE

और फिर सीमांकक से पहले सामान बाहर निकालें:

awk -F, '{print $2 "|" $line}' | grep -v ^BAD_VALUE | sed 's/.*|//g'

(नोट-यह sed कमांड मैला है क्योंकि इसमें भागने के मूल्य शामिल नहीं हैं। इसके अलावा sed पैटर्न वास्तव में "[^ |] +" की तरह होना चाहिए (यानी कुछ भी नहीं)।


3
वह लाइनों को शुद्ध नहीं करना चाहता है, वह एक विशिष्ट स्ट्रिंग के साथ एक पंक्ति की एक प्रति को बनाए रखना चाहता है। यूनीक सही उपयोग का मामला है।
पहुंचना

-3

sortपहले फ़ाइल को सॉर्ट करके , फिर आप आवेदन कर सकते हैं uniq

ऐसा लगता है कि फ़ाइल ठीक है:

$ cat test.csv
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv | uniq
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

आप कुछ AWK जादू भी कर सकते हैं:

$ awk -F, '{ lines[$1] = $0 } END { for (l in lines) print lines[l] }' test.csv
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 

यह कॉलम अद्वितीय नहीं है जैसा कि प्रश्न में पूछा गया है। यह पूरी लाइन के लिए अद्वितीय है। इसके अलावा, आप एक यूनीक करने के लिए एक तरह से करने की जरूरत नहीं है। दोनों परस्पर अनन्य हैं।
जावीद जमा सिप

1
हाँ आप सही है। अंतिम उदाहरण वही करता है जो प्रश्न के लिए पूछा जाता है, भले ही स्वीकृत उत्तर बहुत साफ हो। के बारे में sort, तो uniq, sortऐसा करने से पहले किया जाना चाहिए uniqअन्यथा यह काम नहीं करता (लेकिन आप दूसरे आदेश और सिर्फ उपयोग को छोड़ सकते हैं sort -u)। प्रेषक uniq(1): "INPUT (या मानक इनपुट) से आसन्न मिलान लाइनों को फ़िल्टर करें, OUTPUT (या मानक आउटपुट) को लिख रहा है।"
मिकेल एस

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