यहाँ पर विचार करने के लिए कई चीजें हैं।
i=`cat input`
महंगा हो सकता है और गोले के बीच बहुत भिन्नताएं हैं।
यह एक सुविधा है जिसे कमांड प्रतिस्थापन कहा जाता है। यह विचार कमांड के पूरे आउटपुट को i
मेमोरी में परिवर्तनशील न्यूलाइन वर्णों में माइनस करने के लिए है ।
ऐसा करने के लिए, गोले को एक उपखंड में कमांड को फोर्क करें और एक पाइप या सॉकेटपेयर के माध्यम से इसके आउटपुट को पढ़ें। आप यहाँ बहुत भिन्नता देखते हैं। यहाँ 50MiB फ़ाइल पर, मैं उदाहरण के लिए kash93 की तुलना में 6 गुना धीमा, लेकिन zsh की तुलना में थोड़ा तेज़ और दो बार तेज़ होने के रूप में देख सकता हूँ yash
।
bash
धीमा होने का मुख्य कारण यह है कि यह पाइप से एक बार में 128 बाइट्स (जबकि अन्य गोले 4KiB या 8KiB एक समय में पढ़ता है) से पढ़ता है और सिस्टम कॉल ओवरहेड द्वारा दंडित किया जाता है।
zsh
एनयूएल बाइट्स (एनयूएल बाइट्स पर अन्य गोले तोड़ने) से बचने के लिए कुछ पोस्ट-प्रोसेसिंग करने की आवश्यकता है, और yash
मल्टी-बाइट वर्णों को पार्स करके और भी भारी-शुल्क प्रसंस्करण करता है।
सभी गोले को अनुगामी न्यूलाइन वर्णों को स्ट्रिप करने की आवश्यकता होती है जो वे कम या ज्यादा कुशलता से कर सकते हैं।
कुछ एनयूएल बाइट्स को दूसरों की तुलना में अधिक सुंदर तरीके से संभालना चाहते हैं और उनकी उपस्थिति की जांच कर सकते हैं।
फिर एक बार जब आपके पास स्मृति में वह बड़ा चर होता है, तो उस पर किसी भी हेरफेर में आम तौर पर अधिक मेमोरी आवंटित करना और डेटा को कॉपी करना शामिल होता है।
यहां, आप चर की सामग्री को पारित करने के लिए (पास करने का इरादा कर रहे थे) कर रहे हैं echo
।
सौभाग्य से, echo
आपके शेल में अंतर्निहित है, अन्यथा एर्ग सूची में बहुत लंबी त्रुटि के साथ निष्पादन विफल हो जाता । फिर भी, तर्क सूची सरणी का निर्माण संभवतः चर की सामग्री की नकल करना शामिल होगा।
आपके कमांड प्रतिस्थापन दृष्टिकोण में अन्य मुख्य समस्या यह है कि आप विभाजन + ग्लोब ऑपरेटर (चर को उद्धृत करने के लिए भूलकर) को लागू कर रहे हैं ।
उसके लिए, गोले को वर्णों की एक स्ट्रिंग के रूप में स्ट्रिंग का इलाज करने की आवश्यकता है (हालांकि कुछ गोले नहीं हैं और उस संबंध में छोटी गाड़ी हैं) तो UTF-8 स्थानों में, इसका मतलब है कि UTF-8 अनुक्रमों को पार्स करना (यदि पहले से ऐसा नहीं किया गया yash
है) , $IFS
स्ट्रिंग में पात्रों के लिए देखें। यदि $IFS
स्थान, टैब या न्यूलाइन (जो डिफ़ॉल्ट रूप से मामला है), एल्गोरिथ्म और भी जटिल और महंगा है। फिर, उस विभाजन से उत्पन्न शब्दों को आवंटित और कॉपी करने की आवश्यकता होती है।
ग्लोब वाला हिस्सा और भी महंगा होगा। तो उन शब्दों में से किसी ग्लोब वर्ण हो ( *
, ?
, [
), तो खोल कुछ निर्देशिका की सामग्री पढ़ सकते हैं और कुछ महंगे पैटर्न मिलान करना होगा ( bash
उदाहरण के लिए के कार्यान्वयन के लिए कुख्यात है कि कम से बहुत बुरा है)।
यदि इनपुट में कुछ ऐसा है /*/*/*/../../../*/*/*/../../../*/*/*
, तो यह बहुत महंगा होगा क्योंकि इसका अर्थ है हजारों निर्देशिकाओं को सूचीबद्ध करना और यह कई सौ MiB तक विस्तारित हो सकता है।
फिर echo
आम तौर पर कुछ अतिरिक्त प्रसंस्करण करेंगे। कुछ कार्यान्वयन \x
तर्क में प्राप्त होने वाले अनुक्रमों का विस्तार करते हैं, जिसका अर्थ है कि सामग्री को पार्स करना और संभवतः डेटा का एक और आवंटन और प्रतिलिपि।
दूसरी ओर, ठीक है, अधिकांश शेल cat
में बिल्ट-इन नहीं है, इसलिए इसका मतलब है कि एक प्रक्रिया को फोर्क करना और इसे निष्पादित करना (इसलिए कोड और लाइब्रेरी लोड करना), लेकिन पहले मंगलाचरण के बाद, वह कोड और इनपुट फ़ाइल की सामग्री स्मृति में कैश किया जाएगा। दूसरी ओर, कोई मध्यस्थ नहीं होगा। cat
एक समय में बड़ी मात्रा में पढ़ेगा और इसे बिना प्रसंस्करण के सीधे लिख देगा, और इसे बड़ी मात्रा में मेमोरी आवंटित करने की आवश्यकता नहीं है, बस एक बफर जो इसे पुन: उपयोग करता है।
इसका मतलब यह भी है कि यह बहुत अधिक विश्वसनीय है क्योंकि यह एनयूएल बाइट्स पर चोक नहीं करता है और अनुगामी न्यूलाइन वर्णों को ट्रिम नहीं करता है (और विभाजित + ग्लोब नहीं करता है, हालांकि आप चर को उद्धृत करके इससे बच सकते हैं, और नहीं से बचने के अनुक्रम का विस्तार करें, हालांकि आप printf
इसके बजाय echo
) से बच सकते हैं ।
यदि आप इसे cat
कई बार लागू करना चाहते हैं, तो कई बार लागू करने के बजाय , केवल input
कई बार पास करें cat
।
yes input | head -n 100 | xargs cat
100 के बजाय 3 कमांड चलाएंगे।
चर संस्करण को अधिक विश्वसनीय बनाने के लिए, आपको उपयोग करने की आवश्यकता होगी zsh
(अन्य शेल NUL बाइट्स के साथ सामना नहीं कर सकते हैं) और इसे करें:
zmodload zsh/mapfile
var=$mapfile[input]
repeat 10 print -rn -- "$var"
अगर आपको पता है कि इनपुट में NUL बाइट्स नहीं हैं, तो आप मज़बूती से इसे POSIXly कर सकते हैं (हालाँकि यह काम नहीं कर सकता जहाँ बिल्ट printf
नहीं है):
i=$(cat input && echo .) || exit # add an extra .\n to avoid trimming newlines
i=${i%.} # remove that trailing dot (the \n was removed by cmdsubst)
n=10
while [ "$n" -gt 10 ]; do
printf %s "$i"
n=$((n - 1))
done
लेकिन यह cat
लूप में उपयोग करने की तुलना में कभी भी अधिक कुशल नहीं होगा (जब तक कि इनपुट बहुत छोटा न हो)।
cat $(for i in $(seq 1 10); do echo "input"; done) >> output
? :)