लिनक्स उपयोगकर्ताओं के लिए अद्यतन 2020:
यदि आपके पास bash (4.4-अल्फ़ा या बेहतर) का अप-टू-डेट संस्करण है, जैसा कि आप शायद लिनक्स पर हैं, तो आप बेंजामिन डब्ल्यू के उत्तर का उपयोग करें ।
यदि आप Mac OS पर हैं, जिसे मैंने चेक किया था- तब भी bash 3.2 का उपयोग किया गया था, या अन्यथा पुराने बैश का उपयोग कर रहे हैं, तो अगले भाग पर जारी रखें।
बैश 4.3 या उससे पहले का उत्तर
सरणी find
में आउटपुट प्राप्त करने के लिए यहां एक समाधान है bash
:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
यह मुश्किल है, क्योंकि सामान्य तौर पर, फ़ाइल नामों में रिक्त स्थान, नई लाइनें और अन्य स्क्रिप्ट-शत्रुतापूर्ण अक्षर हो सकते हैं। find
फ़ाइल नामों को सुरक्षित रूप से उपयोग करने और एक-दूसरे से अलग करने का एकमात्र तरीका यह है कि उपयोग करने के लिए -print0
फ़ाइल नामों को एक अशक्त चरित्र के साथ अलग किया जाए। यदि बैश readarray
/ mapfile
कार्यों ने अशक्त-पृथक तारों का समर्थन किया, तो यह बहुत असुविधा नहीं होगी, लेकिन वे नहीं करते हैं। बैश read
करता है और जो हमें ऊपर लूप में ले जाता है।
[यह जवाब मूल रूप से 2014 में लिखा गया था। यदि आपके पास बैश का हालिया संस्करण है, तो कृपया नीचे अपडेट देखें।]
यह काम किस प्रकार करता है
पहली पंक्ति एक खाली सरणी बनाती है: array=()
हर बार जब read
कथन निष्पादित किया जाता है, तो मानक इनपुट से एक अशक्त-पृथक फ़ाइल नाम पढ़ा जाता है। -r
विकल्प बताता read
बैकस्लैश वर्ण अकेला छोड़ने के लिए। -d $'\0'
बताता है read
कि इनपुट अशक्त-अलग हो जाएगा। चूंकि हम नाम को छोड़ देते हैं read
, शेल इनपुट को डिफ़ॉल्ट नाम में डालता है REPLY
:।
array+=("$REPLY")
बयान सरणी के लिए नया फ़ाइल नाम संलग्न कर देता है array
।
अंतिम पंक्ति लूप find
के मानक इनपुट के आउटपुट प्रदान करने के लिए पुनर्निर्देशन और कमांड प्रतिस्थापन को जोड़ती है while
।
प्रक्रिया प्रतिस्थापन का उपयोग क्यों करें?
यदि हम प्रक्रिया प्रतिस्थापन का उपयोग नहीं करते हैं, तो लूप को इस प्रकार लिखा जा सकता है:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
ऊपर के आउटपुट find
में एक अस्थायी फ़ाइल में संग्रहीत किया जाता है और उस फ़ाइल का उपयोग मानक इनपुट के रूप में लूप में किया जाता है। प्रक्रिया प्रतिस्थापन का विचार ऐसी अस्थायी फ़ाइलों को अनावश्यक बनाने के लिए है। इसलिए, while
लूप के स्टाइन को प्राप्त करने के बजाय tmpfile
, हम इसे स्टड से प्राप्त कर सकते हैं <(find . -name ${input} -print0)
।
प्रक्रिया प्रतिस्थापन व्यापक रूप से उपयोगी है। कई स्थानों पर जहां कोई कमांड किसी फ़ाइल से पढ़ना चाहता है , आप <(...)
फ़ाइल नाम के बजाय , प्रक्रिया प्रतिस्थापन निर्दिष्ट कर सकते हैं । एक अनुरूप रूप है, >(...)
जिसका उपयोग फ़ाइल नाम के स्थान पर किया जा सकता है जहां कमांड फ़ाइल में लिखना चाहता है ।
सरणियों की तरह, प्रक्रिया प्रतिस्थापन बैश और अन्य उन्नत गोले की एक विशेषता है। यह POSIX मानक का हिस्सा नहीं है।
वैकल्पिक: lastpipe
यदि वांछित है, तो lastpipe
प्रक्रिया प्रतिस्थापन (हैट टिप: सीज़र ) के बजाय इस्तेमाल किया जा सकता है :
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipe
बश को वर्तमान शेल (पृष्ठभूमि नहीं) में पाइप लाइन में अंतिम कमांड चलाने के लिए कहता है। इस तरह, array
पाइपलाइन पूरी होने के बाद अस्तित्व में रहता है। क्योंकि lastpipe
जॉब कंट्रोल बंद होने पर ही हम प्रभावी होते हैं set +m
। (स्क्रिप्ट में, कमांड लाइन के विपरीत, नौकरी नियंत्रण डिफ़ॉल्ट रूप से बंद है।)
अतिरिक्त नोट्स
निम्न आदेश शेल चर बनाता है, शेल सरणी नहीं:
array=`find . -name "${input}"`
यदि आप एक सरणी बनाना चाहते हैं, तो आपको खोज के आउटपुट के आसपास पार्न्स लगाने की आवश्यकता होगी। इसलिए, भोलेपन से, एक:
array=(`find . -name "${input}"`)
समस्या यह है कि शेल शब्द विभाजन के परिणामों को निष्पादित करता है find
ताकि सरणी के तत्वों की गारंटी न हो कि आप क्या चाहते हैं।
अपडेट 2019
संस्करण 4.4-अल्फा के साथ शुरू, बैश अब एक -d
विकल्प का समर्थन करता है ताकि उपरोक्त लूप अब आवश्यक न हो। इसके बजाय, एक का उपयोग कर सकते हैं:
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
इस बारे में अधिक जानकारी के लिए कृपया बेंजामिन डब्ल्यू का जवाब देखें (और अपवोट करें) ।