बैश आंतरिक रूप से सी-स्टाइल स्ट्रिंग्स का उपयोग करता है, जिन्हें नल बाइट्स द्वारा समाप्त किया जाता है। इसका मतलब यह है कि एक बैश स्ट्रिंग (जैसे कि एक चर का मान, या एक कमांड का तर्क) वास्तव में एक अशक्त बाइट नहीं हो सकता है। उदाहरण के लिए, यह मिनी स्क्रिप्ट:
foobar=$'foo\0bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
वास्तव में प्रिंट करता है 3
, क्योंकि $foobar
वास्तव में बस है 'foo'
: bar
स्ट्रिंग के अंत के बाद आता है।
इसी तरह, echo $'foo\0bar'
सिर्फ प्रिंट foo
, क्योंकि भाग के echo
बारे में पता नहीं है \0bar
।
जैसा कि आप देख सकते हैं, \0
अनुक्रम वास्तव में एक $'...'
इनस्टाइल स्ट्रिंग में बहुत भ्रामक है ; यह स्ट्रिंग के अंदर एक अशक्त बाइट की तरह दिखता है, लेकिन यह इस तरह से काम नहीं करता है। आपके पहले उदाहरण में, आपकी read
आज्ञा है -d $'\0'
। यह काम करता है, लेकिन केवल इसलिए -d ''
भी काम करता है! (यह स्पष्ट रूप से प्रलेखित विशेषता नहीं है read
, लेकिन मुझे लगता है कि यह एक ही कारण के लिए काम करता है: ''
खाली स्ट्रिंग है, इसलिए इसकी समाप्ति नल बाइट तुरंत आती है। इसे " डेलिम के पहले चरित्र" का उपयोग करने के रूप में प्रलेखित किया गया है , और मुझे लगता है कि यह काम करता है। अगर "पहला चरित्र" स्ट्रिंग के अंत में है! "-d delim
लेकिन जैसा कि आप अपने से पता find
उदाहरण के लिए, यह है एक कमांड एक अशक्त बाइट प्रिंट करने के लिए, और कहा कि बाइट एक और आदेश है कि यह इनपुट के रूप में पढ़ता को पहुंचाया जा करने के लिए के लिए संभव। उस का कोई हिस्सा बैश के अंदर एक स्ट्रिंग में एक अशक्त बाइट भंडारण पर निर्भर करता है । आपके दूसरे उदाहरण के साथ एकमात्र समस्या यह है कि हम $'\0'
कमांड के तर्क में उपयोग नहीं कर सकते हैं ; echo "$file"$'\0'
खुशी से अंत में नल बाइट प्रिंट कर सकता है, अगर केवल यह जानता था कि आप इसे चाहते थे।
इसलिए उपयोग करने के बजाय echo
, आप उपयोग कर सकते हैं printf
, जो $'...'
-स्टाइल स्ट्रिंग्स के रूप में एक ही तरह के एस्केप सीक्वेंस का समर्थन करता है । इस तरह, आप एक स्ट्रिंग के अंदर एक शून्य बाइट के बिना एक नल बाइट मुद्रित कर सकते हैं। यह इस तरह दिखेगा:
for file in * ; do printf '%s\0' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
या बस यह:
printf '%s\0' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
(ध्यान दें: echo
वास्तव में एक -e
ध्वज भी होता है जो इसे \0
एक सुस्त बाइट को संसाधित करने और प्रिंट करने देता है; लेकिन फिर यह आपके फ़ाइल नाम में किसी विशेष क्रम को संसाधित करने का भी प्रयास करेगा। इसलिए printf
दृष्टिकोण अधिक मजबूत है।)
संयोग से, वहाँ कुछ गोले कि कर रहे हैं करते अशक्त अंदर तार बाइट्स अनुमति देते हैं। आपका उदाहरण Zsh में ठीक काम करता है, उदाहरण के लिए (डिफ़ॉल्ट सेटिंग्स मानकर)। हालाँकि, आपके शेल की परवाह किए बिना, यूनिक्स-जैसे ऑपरेटिंग सिस्टम, प्रोग्राम के लिए तर्कों के अंदर नल बाइट्स को शामिल करने का एक तरीका प्रदान नहीं करते हैं (क्योंकि प्रोग्राम तर्क को सी-स्टाइल स्ट्रिंग्स के रूप में पारित किया जाता है), इसलिए हमेशा कुछ सीमाएं होंगी। (आपका उदाहरण केवल Zsh में काम कर सकता है क्योंकि echo
एक शेल बिल्डिन है, इसलिए Zsh अन्य कार्यक्रमों को लागू करने के लिए OS समर्थन पर भरोसा किए बिना इसे लागू कर सकता है। यदि आप command echo
इसके बजाय उपयोग करते हैं echo
, ताकि यह बिलिन को बायपास कर दे और स्टैंडअलोन echo
प्रोग्राम का उपयोग कर सके $PATH
, आप ज़श में वैसा ही व्यवहार देखेंगे जैसे बैश में।)
-d ''
पहले से ही परिसीमन करने का मतलब है तो IFS कुछ भी क्यों नहीं सेट करता है\0
? मुझे यहाँ एक स्पष्टीकरण मिला: stackoverflow.com/questions/8677546/…