आइए एक उदाहरण देखें, कुछ ध्यान से तैयार किए गए इनपुट टेक्स्ट के साथ:
text=' hello world\
foo\bar'
यह दो पंक्तियाँ हैं, पहली शुरुआत अंतरिक्ष से होती है और एक बैकस्लैश के साथ समाप्त होती है। पहले, आइए देखें कि बिना किसी सावधानी के क्या होता है read
(लेकिन विस्तार के किसी भी जोखिम के बिना printf '%s\n' "$text"
सावधानीपूर्वक प्रिंट करने के लिए $text
)। (नीचे, $
शेल प्रॉम्प्ट है।)
$ printf '%s\n' "$text" |
while read line; do printf '%s\n' "[$line]"; done
[hello worldfoobar]
read
बैकस्लैश खा लिया: बैकस्लैश-न्यूलाइन की वजह से न्यूलाइन को अनदेखा किया जा सकता है, और बैकस्लैश-कुछ भी पहले बैकस्लैश को अनदेखा करता है। विशेष रूप से इलाज किए जा रहे बैकस्लैश से बचने के लिए, हम उपयोग करते हैं read -r
।
$ printf '%s\n' "$text" |
while read -r line; do printf '%s\n' "[$line]"; done
[hello world\]
[foo\bar]
यह बेहतर है, हमारे पास उम्मीद के मुताबिक दो लाइनें हैं। दो पंक्तियों में लगभग वांछित सामग्री होती है: इसके बीच का दोहरा स्थान hello
और world
बरकरार रखा गया है, क्योंकि यह line
चर के भीतर है । दूसरी ओर, प्रारंभिक स्थान खा लिया गया था। ऐसा इसलिए read
है क्योंकि आप इसे चर के रूप में कई शब्दों के रूप में पढ़ता है, सिवाय इसके कि अंतिम चर में बाकी पंक्ति होती है - लेकिन यह अभी भी पहले शब्द से शुरू होता है, अर्थात प्रारंभिक स्थान छोड़ दिए जाते हैं।
इसलिए, प्रत्येक पंक्ति को शाब्दिक रूप से पढ़ने के लिए, हमें यह सुनिश्चित करने की आवश्यकता है कि कोई शब्द विभाजन नहीं हो रहा है। हम IFS
चर को एक खाली मान पर सेट करके ऐसा करते हैं ।
$ printf '%s\n' "$text" |
while IFS= read -r line; do printf '%s\n' "[$line]"; done
[ hello world\]
[foo\bar]
ध्यान दें कि हम IFS
विशेष रूप से read
अंतर्निहित अवधि के लिए कैसे सेट करते हैं । IFS= read -r line
सेट वातावरण चर IFS
विशेष रूप से के निष्पादन के लिए (एक खाली मूल्य के लिए) read
। यह सामान्य सरल कमांड सिंटैक्स का एक उदाहरण है : चर असाइनमेंट का अनुक्रम (संभवतः खाली) एक कमांड नाम और उसके तर्क (इसके बाद भी, आप किसी भी बिंदु पर पुनर्निर्देशन में फेंक सकते हैं)। चूंकि read
एक अंतर्निर्मित है, चर वास्तव में बाहरी प्रक्रिया के वातावरण में समाप्त नहीं होता है; फिर भी मूल्य $IFS
है कि जब तक हम read
निष्पादित कर रहे हैं, तब तक हम क्या कर रहे हैं । ध्यान दें कि read
एक विशेष अंतर्निहित नहीं है , इसलिए असाइनमेंट केवल इसकी अवधि के लिए रहता है।
इस प्रकार हम इस बात पर ध्यान दे रहे हैं IFS
कि उस पर निर्भर अन्य निर्देशों के मूल्य को न बदलें । यह कोड किसी भी तरह से काम नहीं करेगा जो कि आसपास के कोड ने IFS
शुरू में सेट किया है, और यह किसी भी परेशानी का कारण नहीं होगा यदि लूप के अंदर का कोड निर्भर करता है IFS
।
इस कोड स्निपेट के साथ विरोध करें, जो एक बृहदान्त्र-पृथक पथ में फ़ाइलों को देखता है। फ़ाइल नामों की सूची एक फ़ाइल, प्रति पंक्ति एक फ़ाइल नाम से पढ़ी जाती है।
IFS=":"; set -f
while IFS= read -r name; do
for dir in $PATH; do
## At this point, "$IFS" is still ":"
if [ -e "$dir/$name" ]; then echo "$dir/$name"; fi
done
done <filenames.txt
यदि लूप होता while IFS=; read -r name; do …
, तो बृहदान्त्र-पृथक घटकों में for dir in $PATH
विभाजित नहीं होता $PATH
। यदि कोड था IFS=; while read …
, तो यह और भी स्पष्ट होगा कि लूप बॉडी में IFS
सेट नहीं :
है।
बेशक, IFS
निष्पादित करने के बाद मूल्य को बहाल करना संभव होगा read
। लेकिन इसके लिए पिछले मूल्य को जानने की आवश्यकता होगी, जो अतिरिक्त प्रयास है। IFS= read
सरल तरीका है (और, सुविधाजनक रूप से, सबसे छोटा तरीका भी)।
¹ और, यदि read
फंसे सिग्नल द्वारा बाधित किया जाता है, संभवतः जब जाल निष्पादित हो रहा है - यह POSIX द्वारा निर्दिष्ट नहीं है और अभ्यास में शेल पर निर्भर करता है।
while IFS=X read
पर विभाजित नहीं करता हैX
, लेकिनwhile IFS=X; read
...