स्वीकृत / उच्च मत वाले उत्तर महान हैं, लेकिन उनके पास थोड़े नटखट विवरणों का अभाव है। यह पोस्ट उन मामलों को कवर करती है कि शेल पथ-नाम विस्तार (ग्लोब) के विफल होने पर बेहतर तरीके से कैसे हैंडल किया जाए, जब फ़ाइलनाम में एम्बेडेड newlines / डैश प्रतीक होते हैं और कमांड आउटपुट को फिर से लूप के लिए आउट-लूप से स्थानांतरित करते हुए परिणाम लिखते हैं। फ़ाइल।
जब शेल ग्लोब विस्तार का उपयोग करते हुए चल रहा है, *
तो विस्तार के विफल होने की संभावना है यदि निर्देशिका में मौजूद फाइलें नहीं हैं और एक विस्तारित-विस्तारित ग्लोब स्ट्रिंग को चलाने के लिए कमांड में पारित किया जाएगा, जिसके अवांछनीय परिणाम हो सकते हैं। bash
खोल इस का उपयोग कर के लिए एक विस्तारित खोल विकल्प प्रदान करता है nullglob
। तो लूप मूल रूप से आपकी फ़ाइलों वाली निर्देशिका के अंदर निम्नानुसार हो जाता है
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
यह आपको लूप के लिए सुरक्षित रूप से बाहर निकलने देता है जब अभिव्यक्ति ./*
किसी भी फाइल को नहीं लौटाती है (यदि निर्देशिका खाली है)
या एक POSIX शिकायत तरह से ( nullglob
है bash
विशिष्ट)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
यह आपको लूप के अंदर जाने देता है जब अभिव्यक्ति एक बार के लिए विफल हो जाती है और स्थिति की [ -f "$file" ]
जांच करता है कि क्या संयुक्त राष्ट्र का विस्तारित स्ट्रिंग ./*
उस निर्देशिका में एक वैध फ़ाइल नाम है, जो नहीं होगा। इस स्थिति में विफलता के कारण, continue
हम for
लूप में फिर से शुरू करते हैं जो बाद में नहीं चलेगा।
--
फ़ाइल नाम तर्क पास करने से ठीक पहले के उपयोग पर भी ध्यान दें । यह आवश्यक है क्योंकि जैसा कि पहले उल्लेख किया गया है, शेल फ़ाइल नाम में फ़ाइल नाम में कहीं भी डैश हो सकते हैं। शेल कमांड में से कुछ व्याख्या करते हैं और उन्हें एक कमांड विकल्प के रूप में मानते हैं जब नाम ठीक से उद्धृत नहीं किया जाता है और कमांड सोच को निष्पादित करता है यदि झंडा प्रदान किया गया है।
--
संकेत है कि मामले में जो साधन में कमांड लाइन विकल्प के अंत में, आदेश आदेश झंडे के रूप में इस बिंदु से परे है, लेकिन केवल फ़ाइल नाम के रूप में किसी भी तार पार्स नहीं करना चाहिए।
फ़ाइलनामों को डबल-कोट करना उन मामलों को ठीक से हल करता है जब नामों में ग्लोब कैरेक्टर या व्हाइट-स्पेस होते हैं। लेकिन * निक्स फाइलनाम भी उनमें नई भूमिकाएं शामिल कर सकते हैं। इसलिए हम एकमात्र चरित्र वाले फ़ाइलनाम को डी-लिमिट करते हैं जो मान्य फ़ाइल नाम का हिस्सा नहीं हो सकता है - नल बाइट ( \0
)। चूंकि bash
आंतरिक रूप से C
स्टाइल स्ट्रिंग्स का उपयोग करता है जिसमें स्ट्रिंग के अंत को इंगित करने के लिए नल बाइट्स का उपयोग किया जाता है, यह इसके लिए सही उम्मीदवार है।
तो कमांड printf
के -d
विकल्प का उपयोग करके इस NULL बाइट के साथ फ़ाइलों को सीमांकित करने के लिए शेल के विकल्प का उपयोग करना read
, हम नीचे कर सकते हैं
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
nullglob
और printf
चारों ओर लिपटा कर रहे हैं (..)
, जिसका अर्थ है कि वे मूल रूप से एक उप खोल (बच्चे खोल) में चलाए जा रहे हैं क्योंकि से बचने के लिए nullglob
एक बार आदेश बाहर निकलता है, माता पिता के खोल पर प्रतिबिंबित करने के लिए विकल्प। -d ''
का विकल्प read
आदेश है नहीं POSIX शिकायत है, तो एक की जरूरत है bash
खोल यह किया जाए। find
कमांड का उपयोग करके इसे किया जा सकता है
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
उन find
कार्यान्वयनों के लिए जो समर्थन नहीं करते -print0
(GNU और FreeBSD कार्यान्वयन के अलावा), इसका उपयोग करके अनुकरण किया जा सकता हैprintf
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
एक अन्य महत्वपूर्ण सुधार, आई-ओ की एक उच्च संख्या को कम करने के लिए फॉर-लूप से फिर से दिशा को स्थानांतरित करना है। लूप के अंदर उपयोग किए जाने पर, शेल को लूप के प्रत्येक पुनरावृत्ति के लिए सिस्टम-कॉल को दो बार निष्पादित करना पड़ता है, एक बार खोलने के लिए और एक बार फाइल से जुड़े फाइल डिस्क्रिप्टर को बंद करने के लिए। यह बड़े पुनरावृत्तियों को चलाने के लिए आपके प्रदर्शन पर एक बोतल-गर्दन बन जाएगा। अनुशंसित सुझाव इसे लूप के बाहर ले जाने के लिए होगा।
इस सुधार के साथ उपरोक्त कोड का विस्तार, आप कर सकते हैं
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
जो मूल रूप से stdout में आपकी फ़ाइल इनपुट के प्रत्येक पुनरावृत्ति के लिए आपकी कमांड की सामग्री को डाल देगा और जब लूप समाप्त हो जाएगा, तो स्टडआउट की सामग्री लिखने और उसे सहेजने के लिए एक बार लक्ष्य फ़ाइल खोलें। find
उसी के बराबर संस्करण होगा
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out