बैकटिक (या $ (...)) के विस्तार में रिक्त स्थान की रक्षा करने का कोई तरीका नहीं है?
नहीं, वहाँ नहीं है। ऐसा क्यों है?
बैश को यह जानने का कोई तरीका नहीं है कि क्या संरक्षित किया जाना चाहिए और क्या नहीं।
यूनिक्स फ़ाइल / पाइप में कोई सरणियाँ नहीं हैं। यह सिर्फ एक बाइट स्ट्रीम है। कमांड के अंदर ``
या $()
स्ट्रीम को आउटपुट करता है, जो निगलता है और एकल स्ट्रिंग के रूप में व्यवहार करता है। उस बिंदु के रूप में, आपके पास केवल दो विकल्प हैं: इसे उद्धरण में रखें, इसे एक स्ट्रिंग के रूप में रखने के लिए, या इसे नग्न रखें, ताकि बैश अपने कॉन्फ़िगर किए गए व्यवहार के अनुसार इसे विभाजित कर सके।
तो आपको क्या करना है यदि आप चाहते हैं कि एक सरणी एक बाइट प्रारूप को परिभाषित करे जिसमें एक सरणी हो, और यही उपकरण है जैसे xargs
और find
क्या करें: यदि आप उन्हें -0
तर्क के साथ चलाते हैं , तो वे एक बाइनरी सरणी प्रारूप के अनुसार काम करते हैं जो तत्वों को समाप्त करता है अशक्त बाइट, अन्यथा अपारदर्शी बाइट स्ट्रीम के लिए शब्दार्थ जोड़ना।
दुर्भाग्य से, bash
नल बाइट पर स्ट्रिंग्स को विभाजित करने के लिए कॉन्फ़िगर नहीं किया जा सकता है। हमें दिखाने के लिए /unix//a/110108/17980 का धन्यवाद zsh
।
xargs
आप चाहते हैं कि आपकी आज्ञा एक बार चले, और आपने कहा कि xargs -0 -n 10000
आपकी समस्या का हल है। ऐसा नहीं है, यह सुनिश्चित करता है कि यदि आपके पास 10000 से अधिक पैरामीटर हैं, तो आपकी कमांड एक से अधिक बार चलेगी।
यदि आप इसे सख्ती से या तो एक बार चलाना चाहते हैं या विफल रहते हैं, तो आपको -x
तर्क और -n
तर्क को तर्क से बड़ा प्रदान करना होगा -s
(वास्तव में: इतना बड़ा कि शून्य-लंबाई वाले तर्कों का एक पूरा गुच्छा और साथ ही कमांड का नाम इसमें फिट नहीं होता है) -s
आकार)। ( आदमी xargs , नीचे अंश देखें)
वर्तमान में मैं जिस सिस्टम पर हूं, वह लगभग 8M तक सीमित है, इसलिए यहां मेरी सीमा है:
$ printf '%s\0' -- {1..1302582} | xargs -x0n 2076858 -s 2076858 /bin/true
xargs: argument list too long
$ printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true
(no output)
दे घुमा के
यदि आप किसी बाहरी कमांड को शामिल नहीं करना चाहते हैं, तो पढ़ा गया लूप एक सरणी खिलाता है, जैसा कि /unix//a/110108/17980 में दिखाया गया है , चीजों को विभाजित करने के लिए बैश का एकमात्र तरीका है नल बाइट।
( . ... "$@" )
स्टैक के आकार की सीमा से बचने के लिए स्क्रिप्ट को स्रोत बनाने का विचार अच्छा है (मैंने यह कोशिश की, यह काम करता है!), लेकिन शायद सामान्य परिस्थितियों के लिए महत्वपूर्ण नहीं है।
यदि आप स्टड से कुछ और पढ़ना चाहते हैं, तो प्रक्रिया पाइप के लिए एक विशेष एफडी का उपयोग करना महत्वपूर्ण है, लेकिन अन्यथा आपको इसकी आवश्यकता नहीं होगी।
इसलिए, रोजमर्रा की घरेलू जरूरतों के लिए सबसे सरल "देशी" तरीका:
files=()
while IFS= read -rd '' file; do
files+=("$file")
done <(find ... -print0)
myscriptornonscript "${files[@]}"
यदि आपको अपनी प्रक्रिया पेड़ की तरह साफ और देखने में अच्छी लगती है, तो यह विधि आपको करने की अनुमति देती है exec mynonscript "${files[@]}"
, जो मेमोरी से बैश प्रक्रिया को हटा देती है, इसे तथाकथित कमांड से बदल दिया जाता है। xargs
हमेशा याद में रहेगा जब तक कि कमांड चलता है, भले ही कमांड केवल एक बार चलने वाला हो।
देशी बैश विधि के खिलाफ क्या बोलता है:
$ time { printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true; }
real 0m2.014s
user 0m2.008s
sys 0m0.172s
$ time {
args=()
while IFS= read -rd '' arg; do
args+=( "$arg" )
done < <(printf '%s\0' -- $(echo {1..1302581}))
/bin/true "${args[@]}"
}
bash: /bin/true: Argument list too long
real 107m51.876s
user 107m38.532s
sys 0m7.940s
ऐश हैंडलिंग के लिए बैश को अनुकूलित नहीं किया गया है।
आदमी xargs :
-एन मैक्स-आर्ग्स
प्रति कमांड लाइन में अधिकतम अधिकतम-आर्ग्यूमेंट तर्क का उपयोग करें। अधिकतम-आर्ग्यूमेंट तर्क से कम का उपयोग किया जाएगा यदि आकार (-s विकल्प देखें) को पार कर जाता है, जब तक कि -x विकल्प नहीं दिया जाता है, जिस स्थिति में xargs बाहर निकल जाएगा।
-s अधिकतम-वर्ण
प्रति पंक्ति में अधिकतम-वर्ण वर्णों का उपयोग करें, जिसमें कमांड और प्रारंभिक-तर्क और तर्क तार के सिरों पर समाप्ति नल शामिल हैं। सबसे बड़ी अनुमत मूल्य प्रणाली-निर्भर है, और निष्पादन के लिए तर्क लंबाई सीमा के रूप में गणना की जाती है, आपके वातावरण का आकार कम, हेडरूम के 2048 बाइट्स। यदि यह मान 128KiB से अधिक है, तो डिफ़ॉल्ट मान के रूप में 128Kib का उपयोग किया जाता है; अन्यथा, डिफ़ॉल्ट मान अधिकतम है। 1KiB 1024 बाइट्स है।
-एक्स
यदि आकार (-s विकल्प देखें) से अधिक हो तो बाहर निकलें।
IFS="
, न्यूलाइन है"
)। लेकिन क्या सभी फाइलनाम पर स्क्रिप्ट को निष्पादित करने की आवश्यकता है ? यदि नहीं, तो प्रत्येक फ़ाइल के लिए स्क्रिप्ट निष्पादित करने के लिए स्वयं का उपयोग करने पर विचार करें।