2009-03-06 21 views
158

में किसी सूची से अद्वितीय या विशिष्ट मानों का चयन करें मेरे पास एक ksh स्क्रिप्ट है जो मानों की एक लंबी सूची देता है, नई लाइन अलग होती है, और मैं केवल अद्वितीय/विशिष्ट मान देखना चाहता हूं। ऐसा करना संभव है?यूनिक्स शैल स्क्रिप्ट

उदाहरण के लिए, मेरी उत्पादन एक निर्देशिका में फाइल प्रत्यय है:

tar 
gz 
java 
class 

उत्तर

302

आप चाहते हो सकता है:

tar 
gz 
java 
gz 
java 
tar 
class 
class 

मैं की तरह एक सूची देखने के लिए चाहते हैं uniq और sort अनुप्रयोगों को देखने के लिए।

विपरीत क्या किया गया है करने के लिए:

 
./yourscript.ksh | sort | uniq 

संपादित करें (FYI करें, हाँ, तरह इस आदेश पंक्ति में आवश्यक है, uniq केवल डुप्लिकेट लाइनों कि एक दूसरे के बाद तुरंत हैं स्ट्रिप्स) uniq के कमांडलाइन विकल्पों के संबंध में Aaron Digulla द्वारा पोस्ट किया गया:

निम्नलिखित इनपुट को देखते हुए:

 
class 
jar 
jar 
jar 
bin 
bin 
java 

uniq इच्छा आउटपुट सभी लाइनों ठीक एक बार:

 
class 
jar 
bin 
java 

uniq -d इच्छा आउटपुट सभी लाइनों है कि एक से अधिक बार दिखाई देते हैं, और यह उन्हें एक बार प्रिंट होगा:

 
jar 
bin 

uniq -u इच्छा आउटपुट सभी रेखाएं जो बिल्कुल एक बार दिखाई देती हैं, और यह उन्हें एक बार प्रिंट करेगी:

 
class 
java 
+1

देर से आने वालों के लिए बस एक एफवाईआई: @ AaronDigulla का जवाब तब से सही किया गया है। – mklement0

+1

बहुत अच्छा बिंदु यह 'इस कमांड लाइन में क्रमबद्ध है, यूनिक केवल डुप्लिकेट लाइनों को स्ट्रिप्स करता है जो तुरंत एक दूसरे के बाद होते हैं' जो मैंने अभी सीखा है !! – HattrickNZ

+2

जीएनयू 'सॉर्ट' में अद्वितीय मान देने के लिए '-u' संस्करण भी शामिल है। – Arthur2e5

9

उन्हें sort और uniq के माध्यम से पाइप करें। यह सभी डुप्लीकेट हटा देता है।

uniq -d केवल डुप्लिकेट देता है, uniq -u केवल अद्वितीय वाले (डुप्लिकेट स्ट्रिप्स) देता है।

./yourscript.ksh | perl -ne 'if (!defined $x{$_}) { print $_; $x{$_} = 1; }' 

यह इतना है कि यह फिर से उत्पादन यह नहीं है मूल रूप से बस हर पंक्ति उत्पादन याद है:

+0

इसे पहले देखकर क्रमबद्ध करें – Brabster

+1

हाँ, आप करते हैं। या अधिक सटीक रूप से, आपको सभी डुप्लिकेट लाइनों को एक साथ समूहित करने की आवश्यकता है। सॉर्टिंग हालांकि परिभाषा के अनुसार करता है;) –

+0

इसके अलावा, 'uniq -u' डिफ़ॉल्ट व्यवहार नहीं है (विवरण के लिए मेरे उत्तर में संपादन देखें) –

9

बड़े डेटा सेट के लिए जहां छँटाई वांछनीय नहीं हो सकता है, आप निम्न पर्ल स्क्रिप्ट का उपयोग कर सकते हैं।

इसका लाभ "sort | uniq" समाधान पर लाभ है जिसमें कोई सॉर्टिंग आवश्यक नहीं है।

+2

ध्यान दें कि एक बहुत बड़ी फ़ाइल को सॉर्ट करना एक प्रकार का मुद्दा नहीं है; यह उन फ़ाइलों को सॉर्ट कर सकता है जो उपलब्ध रैम + स्वैप से बड़े हैं। पर्ल, ओटीओएच, अगर कुछ ही डुप्लीकेट हैं तो असफल हो जाएंगे। –

+0

हां, यह अपेक्षित डेटा के आधार पर एक व्यापार-बंद है। पर्ल कई डुप्लिकेट के साथ विशाल डेटासेट के लिए बेहतर है (कोई डिस्क-आधारित स्टोरेज आवश्यक नहीं है)। कुछ डुप्लिकेट वाले विशाल डेटासेट को सॉर्ट (और डिस्क स्टोरेज) का उपयोग करना चाहिए। छोटे डेटासेट या तो उपयोग कर सकते हैं। व्यक्तिगत रूप से, मैं पहले पर्ल का प्रयास करता हूं, अगर यह विफल रहता है तो सॉर्ट करने के लिए स्विच करें। – paxdiablo

+0

चूंकि सॉर्ट केवल डिस्क पर स्वैप करना है तो आपको केवल एक लाभ देता है। – paxdiablo

9

zsh आप ऐसा कर सकते के साथ:

zsh-5.0.0[t]% cat infile 
tar 
more than one word 
gz 
java 
gz 
java 
tar 
class 
class 
zsh-5.0.0[t]% print -l "${(fu)$(<infile)}" 
tar 
more than one word 
gz 
java 
class 

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

zsh-4.3.9[t]% awk '!_[$0]++' infile  
tar 
more than one word 
gz 
java 
class 
+2

चालाक समाधान जिनमें इनपुट को सॉर्ट करना शामिल नहीं है। चेतावनी: बहुत चालाक-लेकिन-गुप्त 'अजीक' समाधान (एक स्पष्टीकरण के लिए http://stackoverflow.com/a/21200722/45375 देखें) बड़ी फ़ाइलों के साथ काम करेगा जब तक कि अद्वितीय लाइनों की संख्या छोटी हो पर्याप्त (जैसा अद्वितीय रेखाएं स्मृति में रखी जाती हैं)। 'zsh' समाधान पूरी फ़ाइल को स्मृति में पहले पढ़ता है, जो बड़ी फ़ाइलों के साथ एक विकल्प नहीं हो सकता है। साथ ही, लिखित के रूप में, केवल एम्बेडेड रिक्त स्थान वाली रेखाएं सही ढंग से संभाली जाती हैं; इसे ठीक करने के लिए, 'IFS = $' \ n 'read -d' '-r -A u <फ़ाइल का उपयोग करें; प्रिंट -l $ {(u) u} 'इसके बजाए। – mklement0

+0

सही। या: '(IFS = $ '\ n' u = ($ (

+1

धन्यवाद, यह आसान है (मान लीजिए कि आपको आवश्यकता नहीं है सबहेल के बाहर आवश्यक चर सेट करने के लिए)। मुझे उत्सुकता है कि जब आपको सरणी के सभी तत्वों को संदर्भित करने के लिए '[@] 'प्रत्यय की आवश्यकता होती है - ऐसा लगता है - कम से कम संस्करण 5 के रूप में - यह इसके बिना काम करता है; या आपने इसे स्पष्टता के लिए जोड़ा है? – mklement0

59
./script.sh | sort -u 

यह monoxide'sanswer रूप में ही है, लेकिन थोड़ा अधिक संक्षिप्त।

+4

आप मामूली हो रहे हैं: आपका समाधान भी बेहतर प्रदर्शन करेगा (शायद बड़े डेटा सेट के साथ केवल ध्यान देने योग्य)। – mklement0

1

अनन्य, अनुरोध के अनुसार, (लेकिन क्रमबद्ध नहीं);
~ 70 तत्वों से कम (जैसे समय के साथ परीक्षण) के लिए कम सिस्टम संसाधनों का उपयोग करता है;
, stdin से इनपुट लेने
(या संशोधित करने और किसी अन्य लिपि में शामिल हैं) के लिए लिखा:
(बैश)

bag2set() { 
    # Reduce a_bag to a_set. 
    local -i i j n=${#a_bag[@]} 
    for ((i=0; i < n; i++)); do 
     if [[ -n ${a_bag[i]} ]]; then 
      a_set[i]=${a_bag[i]} 
      a_bag[i]=$'\0' 
      for ((j=i+1; j < n; j++)); do 
       [[ ${a_set[i]} == ${a_bag[j]} ]] && a_bag[j]=$'\0' 
      done 
     fi 
    done 
} 
declare -a a_bag=() a_set=() 
stdin="$(</dev/stdin)" 
declare -i i=0 
for e in $stdin; do 
    a_bag[i]=$e 
    i=$i+1 
done 
bag2set 
echo "${a_set[@]}" 
2

AWK के साथ आप कर सकते हैं, मैं यह तेजी तरह से लगता है

./yourscript.ksh | awk '!a[$0]++' 
संबंधित मुद्दे