बैश में दो सूचियों का अंतर्ग्रहण


163

मैं एक साधारण स्क्रिप्ट लिखने की कोशिश कर रहा हूं जो दो सूचियों में मिली सामग्री को सूचीबद्ध करेगी। सरल बनाने के लिए, आइए उदाहरण के तौर पर ls का उपयोग करें। कल्पना कीजिए "एक" और "दो" निर्देशिका हैं।

one = `ls one`
दो = `ls two`
चौराहा $ एक $ दो

मैं अभी भी हरा रंग में हूं, इसलिए यह महसूस करने के लिए स्वतंत्र हूं कि मैं यह कैसे कर रहा हूं। मुझे बस कुछ कमांड की आवश्यकता है जो "एक" और "दो" में सभी फाइलों को प्रिंट करेगा। दोनों में उनका अस्तित्व होना चाहिए। आप इसे "एक" और "दो" के बीच "प्रतिच्छेदन" कह सकते हैं।


यहाँ कुछ भी वास्तव में इस सवाल का जवाब नहीं देता है: बैश स्क्रिप्ट में दो चरों को कैसे अलग किया जाए।
जेम्सफिशर

मेरी राय में एक नए प्रश्न की तरह लगता है, यह प्रश्न यहाँ स्पष्ट रूप से उत्तर दिया गया है।
जीन-क्रिस्टोफ मीलाउड

यकीनन अधिक उपयोगी दृष्टिकोण लगभग डुप्लिकेट stackoverflow.com/questions/2312762/… में है
ट्रिपल

जवाबों:


285
comm -12  <(ls 1) <(ls 2)

37
विश्वास नहीं कर सकता मुझे commआज तक कोई ज्ञान नहीं था। इसने मेरा पूरा हफ्ता बना दिया :)
दर्रग एनराइट

22
commइनपुट को क्रमबद्ध करने की आवश्यकता होती है। इस मामले में, lsस्वचालित रूप से इसका उत्पादन होता है, लेकिन अन्य उपयोगों को यह करने की आवश्यकता हो सकती है:comm -12 <(some-command | sort) <(some-other-command | sort)
अलेक्जेंडर बर्ड

11
किसी भी चीज़ के लिए आउटपुट का उपयोग न करें। ls इंटरएक्टिव रूप से डायरेक्टरी मेटाडेटा को देखने का एक उपकरण है। कोड के साथ पार्सिंग ls के आउटपुट पर कोई भी प्रयास टूट गया है। ग्लोब अधिक सरल और सही हैं: '' * .txt '' में फाइल के लिए। Mywiki.wooledge.org/ParsingLs
Rani Albeg Wein

2
मैंने इसका उपयोग एक विशेषता द्वारा प्रदान की गई publicविधि के उपयोग को खोजने के प्रयास में किया था, और इसके error()साथ git grepयह अद्भुत था! मैं भाग गया $ comm -12 <(git grep -il "\$this->error(" -- "*.php") <(git grep -il "Dash_Api_Json_Response" -- "*.php"), और सौभाग्य से मैं फ़ाइल के नाम के साथ समाप्त हो गया जिसमें केवल विशेषता थी।
स्थानीयहेज

3
यह उल्लासपूर्ण है। मैं जाग के साथ कुछ पागल सामान करने की कोशिश कर रहा था।
रॉल्फ

55

के साथ समाधान comm

commमहान है, लेकिन वास्तव में क्रमबद्ध सूची के साथ काम करने की आवश्यकता है। और सौभाग्य से हम यहाँ का उपयोग lsजहाँ से lsबैश आदमी पेज

यदि कोई -cftuSUX और न ही -sort में से वर्णानुक्रम में प्रविष्टियों को क्रमबद्ध करें।

comm -12  <(ls one) <(ls two)

के साथ वैकल्पिक sort

दो सूचियों का अंतर्विरोध:

sort <(ls one) <(ls two) | uniq -d

दो सूचियों का सममित अंतर:

sort <(ls one) <(ls two) | uniq -u

बक्शीश

इसके साथ खेलें ;)

cd $(mktemp -d) && mkdir {one,two} && touch {one,two}/file_{1,2}{0..9} && touch two/file_3{0..9}

2
पूरक के बजाय , मुझे लगता है कि आमतौर पर इसे सममित अंतर कहा जाता है
एंड्रयू लाजर

29

commकमांड का उपयोग करें :

ls one | sort > /tmp/one_list
ls two | sort > /tmp/two_list
comm -12 /tmp/one_list /tmp/two_list

"सॉर्ट" वास्तव में आवश्यक नहीं है, लेकिन मैं हमेशा मामले में "कॉम" का उपयोग करने से पहले इसे शामिल करता हूं।


5
इसे शामिल करना अच्छा है क्योंकि इसे क्रमबद्ध करने की आवश्यकता है, और उन्होंने केवल एक उदाहरण के रूप में एलएस का उपयोग किया।
Thor84no

3

एक कम कुशल (कॉम से) वैकल्पिक:

cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -d

1
यदि आप अपनी स्क्रिप्ट में डेबियन / बिन / डैश या कुछ अन्य गैर-बैश शेल का उपयोग कर रहे हैं, तो आप कोष्ठक का उपयोग करके कमांड के आउटपुट को चेन कर सकते हैं (ls 1; ls 2) | sort -u | uniq -d:।
नाइट्रोजन

1
@ MikaëlMayer आपको उस व्यक्ति का नाम चिह्नित करना चाहिए जिसे आप जवाब दे रहे हैं, अन्यथा यह माना जाता है कि आप मेरा मतलब है।
बेनुबर्ड

@nitrogen MikaëlMayer सही है - चिंगिंग sort -u | uniq -dकुछ नहीं करता है, क्योंकि सॉर्ट ने डुप्लिकेट को हटा दिया है इससे पहले कि यूनीक उन्हें ढूंढना शुरू कर दे। मुझे लगता है कि आप समझ नहीं पाए हैं कि मेरी आज्ञा क्या है।
बेनुबर्ड

@Benubird मैं cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -dकुछ भी आउटपुट करने के लिए आपकी कमांड प्राप्त करने में सक्षम नहीं था । मेरा आदेश सूची चौराहे को दिखाने के लिए (ls 1; ls 2) | sort | uniq -d, बिना, पढ़ना चाहिए -u। @ MikaëlMayer सही था कि मेरा मूल आदेश टूट गया था।
नाइट्रोजन

@nitrogen मैं बिल्ली का उपयोग क्यों कर रहा हूं, इसका कारण यह है कि मैं चाहता हूं कि यह एक सामान्य बनाने वाला समाधान हो, ताकि आप lsकिसी और चीज से बदल सकें , जैसे find। आपका समाधान इसकी अनुमति नहीं देता है, क्योंकि यदि कोई आदेश दो पंक्तियों को एक ही देता है, तो वह इसे डुप्लिकेट के रूप में चुनता है। यदि उपयोगकर्ता ls 1/*उपनिर्देशिकाओं की सभी फ़ाइलों को करना और तुलना करना चाहता है तो भी मेरा काम करता है । अन्यथा, हाँ, यह भी काम करता है। यह संभव है खदान विशिष्ट है।
बेनुबर्ड

2

इनपुट और वांछित आउटपुट के आधार पर जॉइन एक और अच्छा विकल्प है

join -j1 -a1 <(ls 1) <(ls 2)

-1

एक और स्टैकओवरफ़्लो प्रश्न है "बैश में ऐरे चौराहा," जो इसे डुप्लिकेट के रूप में चिह्नित किया गया है। मेरे विचार में यह बिल्कुल वैसा नहीं है, क्योंकि यह प्रश्न दो बैश सरणियों की तुलना करने के बारे में बात करता है, जबकि यह प्रश्न बैश फाइलों पर केंद्रित है। अन्य प्रश्न का एक-लाइन उत्तर, जो अब बंद हो गया है, इस प्रकार है:

# List1=( 0 1 2 3 4   6 7 8 9 10 11 12)
# List2=(   1 2 3   5 6   8 9    11 )
# List3=($(comm -12 <(echo ${List1[*]}| tr " " "\n"| sort) <(echo ${List2[*]} | tr " " "\n"| sort)| sort -g))
# echo ${List3[*]}
1 2 3 6 8 9 11

कॉम उपयोगिता एक अल्फ़ान्यूमेरिक प्रकार करती है, जबकि "बैश में ऐरे चौराहे" उत्तर संख्याओं का उपयोग करते हैं; इसलिए "सॉर्ट" और "सॉर्ट -ग" उपयोग।

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