UNIX शेल स्क्रिप्ट में एक सूची से अद्वितीय या अलग मान चुनें


238

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

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

tar
gz
java
gz
java
tar
class
class

मैं एक सूची देखना चाहता हूँ जैसे:

tar
gz
java
class

जवाबों:


432

आप uniqऔर sortअनुप्रयोगों को देखना चाह सकते हैं ।

./yourscript.ksh | सॉर्ट | uniq

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

संपादित करें:

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

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

कक्षा
जार
जार
जार
बिन
बिन
जावा

uniq बिल्कुल एक बार सभी लाइनों का उत्पादन करेगा:

कक्षा
जार
बिन
जावा

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

जार
बिन

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

कक्षा
जावा

2
स्वर्गीय लोगों के लिए बस एक FYI करें: @ AaronDigulla का उत्तर तब से ठीक किया गया है।
mklement0

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

4
GNU में विशिष्ट मान देने के लिए sortएक -uसंस्करण है।
आर्थर

मुझे लगा कि uniqसीम केवल आसन्न रेखाओं (कम से कम डिफ़ॉल्ट रूप से) को संसाधित करने का अर्थ है कि कोई भी sortभोजन करने से पहले इनपुट कर सकता है uniq
स्टेफेन

85
./script.sh | sort -u

यह मोनोऑक्साइड के उत्तर के समान है , लेकिन थोड़ा अधिक संक्षिप्त है।


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

मुझे लगता है कि इससे अधिक कुशल होना चाहिए ... | sort | uniqक्योंकि यह एक शॉट में किया जाता है
एड्रियन एंट्यून्ज़

10

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

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

यह मूल रूप से बस हर लाइन आउटपुट को याद रखता है ताकि वह इसे फिर से आउटपुट न करे।

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


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

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

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

5
यह बहुत अच्छा है जब मैं हर पंक्ति की पहली घटना चाहता हूं। छंटनी कि टूट जाएगा।
१०:३० पर ब्लूयू

10

Zsh के साथ आप ऐसा कर सकते हैं:

% 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 का उपयोग कर सकते हैं:

% awk '!_[$0]++' infile    
tar
more than one word
gz
java
class

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

सही बात। या:(IFS=$'\n' u=($(<infile)); print -l "${(u)u[@]}")
दिमित्रे रादौलोव

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

1
@ mklement0, आप सही कह रहे हैं! जब मैंने पोस्ट लिखी तब मैंने इसके बारे में नहीं सोचा था। वास्तव में, यह पर्याप्त होना चाहिए:print -l "${(fu)$(<infile)}"
दिमित्रे रादोलोव

1
शानदार, आपके पोस्ट को अपडेट करने के लिए धन्यवाद - मैंने awkनमूना आउटपुट को ठीक करने की स्वतंत्रता भी ली।
mklement0

9

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

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


यह लग रहा है द्वारा पहले तरह होगा
brabster

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

इसके अलावा, uniq -uडिफ़ॉल्ट व्यवहार नहीं है (विवरण के लिए मेरे जवाब में संपादन देखें)
मैथ्यू शार्ले

7

AWK के साथ आप कर सकते हैं, मुझे लगता है कि यह तेजी से सॉर्ट करता है

 ./yourscript.ksh | awk '!a[$0]++'

यह निश्चित रूप से काम करने का मेरा पसंदीदा तरीका है, बहुत बहुत धन्यवाद! विशेष रूप से बड़ी फ़ाइलों के लिए, सॉर्ट | uniq- समाधान संभवतः वह नहीं हैं जो आप चाहते हैं।
शमित्ज़ी

1

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

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[@]}"

0

मुझे एक फ़ाइल में गैर-डुप्लिकेट प्रविष्टियाँ प्राप्त करने के लिए एक बेहतर सुझाव मिलता है

awk '$0 != x ":FOO" && NR>1 {print x} {x=$0} END {print}' file_name | uniq -f1 -u
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.