कुछ लोगों के पास वह गलत धारणा है जो readएक पंक्ति को पढ़ने की आज्ञा है। यह।
read(संभवतः बैकस्लैश-कंटिन्यूड) लाइन के शब्दों को पढ़ता है , जहाँ $IFSसीमांकित शब्दों को सीमांकित किया जाता है और सीमांकक (या लाइन्स जारी रखने) से बचने के लिए बैकस्लैश का उपयोग किया जा सकता है।
सामान्य वाक्यविन्यास है:
read word1 word2... remaining_words
readएक समय में stdin एक बाइट पढ़ता है जब तक यह पाता है कोई अनपेक्षित न्यू लाइन चरित्र (या अंत के इनपुट), विभाजन है कि बंटवारे के परिणाम में जटिल नियमों और दुकानों के अनुसार $word1, $word2... $remaining_words।
उदाहरण के लिए इनपुट पर:
<tab> foo bar\ baz bl\ah blah\
whatever whatever
और का डिफ़ॉल्ट मान के साथ $IFS, read a b cआवंटित होगा:
$a ⇐ foo
$b ⇐ bar baz
$c ⇐ blah blahwhatever whatever
अब अगर केवल एक ही तर्क पारित किया गया, तो वह नहीं बनता read line। यह अभी भी है read remaining_words। बैकस्लैश प्रसंस्करण अभी भी किया जाता है, IFS व्हाट्सएप वर्ण अभी भी शुरुआत और अंत से हटा दिए गए हैं।
-rविकल्प बैकस्लैश प्रसंस्करण निकाल देता है। ताकि इसके साथ ही ऊपर के आदेश के -rबजाय असाइन किया जाएगा
$a ⇐ foo
$b ⇐ bar\
$c ⇐ baz bl\ah blah\
अब, बंटवारे वाले हिस्से के लिए, यह महसूस करना महत्वपूर्ण है कि इसके लिए वर्णों के दो वर्ग हैं $IFS: IFS व्हॉट्सएप वर्ण (अर्थात स्थान और टैब (और newline, हालांकि यहां कोई फर्क नहीं पड़ता जब तक कि आप -d का उपयोग न करें), जो भी होता है के डिफ़ॉल्ट मूल्य में $IFS) और अन्य। वर्णों के उन दो वर्गों के लिए उपचार अलग है।
साथ IFS=:( :नहीं एक आईएफएस खाली स्थान के चरित्र जा रहा है), जैसा एक इनपुट :foo::bar::भागों में विभाजित किया "", "foo", "", barऔर ""(और एक अतिरिक्त ""कुछ कार्यान्वयन के साथ कि हालांकि के अलावा कोई फर्क नहीं पड़ता read -a)। जबकि अगर हम इसे :अंतरिक्ष से प्रतिस्थापित करते हैं, तो विभाजन केवल fooऔर में किया जाता है bar। यह प्रमुख है और अनुगामी लोगों की उपेक्षा की जाती है, और उनमें से दृश्यों को एक जैसा माना जाता है। व्हॉट्सएप और नॉन-व्हॉट्सएप कैरेक्टर संयुक्त होने पर अतिरिक्त नियम हैं $IFS। कुछ कार्यान्वयन आईएफएस ( IFS=::या IFS=' ') में पात्रों को दोगुना करके विशेष उपचार को जोड़ / हटा सकते हैं ।
इसलिए, यदि हम नहीं चाहते कि अग्रणी और अनुत्तरित व्हाट्सएप वर्णों को छीन लिया जाए, तो हमें आईएफएस से उन IFS सफेद अंतरिक्ष वर्णों को हटाने की आवश्यकता है।
यहां तक कि भारतीय विदेश सेवा-गैर-सफ़ेद पात्रों के साथ, इनपुट लाइन उन पात्रों में से एक (और केवल एक) होता है और यह (जैसे लाइन के अंतिम वर्ण है कि अगर IFS=: read -r wordकी तरह एक इनपुट पर foo:) POSIX गोले (नहीं के साथ zshहै और न ही कुछ pdkshसंस्करण), कि इनपुट एक fooशब्द के रूप में माना जाता है क्योंकि उन गोले में, वर्णों $IFSको टर्मिनेटर माना जाता है , इसलिए wordइसमें शामिल होगा foo, नहीं foo:।
तो, readबेसिन के साथ इनपुट की एक पंक्ति को पढ़ने के लिए विहित तरीका है:
IFS= read -r line
(ध्यान दें कि ज्यादातर readकार्यान्वयन के लिए, यह केवल पाठ लाइनों के लिए काम करता है क्योंकि NUL वर्ण को छोड़कर समर्थित नहीं है zsh)।
var=value cmdवाक्यविन्यास का उपयोग करना सुनिश्चित करता है कि IFSकेवल उस cmdकमांड की अवधि के लिए अलग-अलग सेट किया गया है ।
इतिहास नोट
readBuiltin बॉर्न शैल द्वारा शुरू की और पढ़ने के लिए पहले से ही किया गया था शब्द , नहीं लाइनों। आधुनिक POSIX गोले के साथ कुछ महत्वपूर्ण अंतर हैं।
बॉर्न शेल readने एक -rविकल्प का समर्थन नहीं किया (जो कोर्न शेल द्वारा पेश किया गया था), इसलिए वहाँ कुछ के साथ इनपुट को पूर्व-प्रसंस्करण के अलावा बैकस्लैश प्रसंस्करण को अक्षम करने का कोई तरीका नहीं है sed 's/\\/&&/g'।
बॉर्न शेल में वर्णों की दो वर्गों की धारणा नहीं थी (जो फिर से ksh द्वारा पेश की गई थी)। बॉर्न में शेल सभी पात्रों को एक ही उपचार कराने के रूप में भारतीय विदेश सेवा खाली स्थान के पात्रों ksh में करते हैं, वह यह है कि IFS=: read a b cजैसा एक इनपुट पर foo::barआवंटित होगा barकरने के लिए $b, नहीं रिक्त स्ट्रिंग।
बॉर्न शेल में, के साथ:
var=value cmd
यदि cmdएक अंतर्निहित (जैसे read) है, तो समाप्त होने के बाद varसेट रहता है । यह विशेष रूप से महत्वपूर्ण है क्योंकि बॉर्न शेल में, विस्तार करने के लिए ही नहीं, सब कुछ विभाजित करने के लिए उपयोग किया जाता है। इसके अलावा, यदि आप बॉर्न शेल में स्पेस कैरेक्टर को हटाते हैं, तो काम नहीं करता है।valuecmd$IFS$IFS$IFS"$@"
बॉर्न शेल में, एक कंपाउंड कमांड को रीडायरेक्ट करने के कारण यह सबस्क्रिप्शन (सबसे शुरुआती संस्करणों में, यहां तक कि जैसी चीजें read var < fileया exec 3< file; read var <&3काम नहीं करता) में चलने का कारण बनता है , इसलिए बॉर्न शेल readमें टर्मिनल पर उपयोगकर्ता इनपुट के लिए कुछ भी उपयोग करना दुर्लभ था (जहां उस लाइन निरंतरता से निपटने की भावना बनी)
कुछ यूनियनों (जैसे कि एचपी / यूएक्स, वहां भी एक है util-linux) में अभी भी lineइनपुट की एक पंक्ति को पढ़ने के लिए एक कमांड है (जो कि एकल यूनिक्स विशिष्टता संस्करण 2 तक एक मानक यूनिक्स कमांड हुआ करता था )।
यह मूल रूप से head -n 1सिवाय इसके कि यह एक बार में एक बाइट पढ़ता है, यह सुनिश्चित करने के लिए कि यह एक पंक्ति से अधिक नहीं पढ़ता है। उन प्रणालियों पर, आप यह कर सकते हैं:
line=`line`
बेशक, इसका मतलब है कि एक नई प्रक्रिया पैदा करना, एक कमांड निष्पादित करना और एक पाइप के माध्यम से इसके आउटपुट को पढ़ना, ताकि ksh की तुलना में बहुत कम कुशल हो IFS= read -r line, लेकिन अभी भी बहुत अधिक सहज है।