आइए एक उदाहरण देखें, कुछ ध्यान से तैयार किए गए इनपुट टेक्स्ट के साथ:
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...