कुछ लोगों के पास वह गलत धारणा है जो 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
कमांड की अवधि के लिए अलग-अलग सेट किया गया है ।
इतिहास नोट
read
Builtin बॉर्न शैल द्वारा शुरू की और पढ़ने के लिए पहले से ही किया गया था शब्द , नहीं लाइनों। आधुनिक POSIX गोले के साथ कुछ महत्वपूर्ण अंतर हैं।
बॉर्न शेल read
ने एक -r
विकल्प का समर्थन नहीं किया (जो कोर्न शेल द्वारा पेश किया गया था), इसलिए वहाँ कुछ के साथ इनपुट को पूर्व-प्रसंस्करण के अलावा बैकस्लैश प्रसंस्करण को अक्षम करने का कोई तरीका नहीं है sed 's/\\/&&/g'
।
बॉर्न शेल में वर्णों की दो वर्गों की धारणा नहीं थी (जो फिर से ksh द्वारा पेश की गई थी)। बॉर्न में शेल सभी पात्रों को एक ही उपचार कराने के रूप में भारतीय विदेश सेवा खाली स्थान के पात्रों ksh में करते हैं, वह यह है कि IFS=: read a b c
जैसा एक इनपुट पर foo::bar
आवंटित होगा bar
करने के लिए $b
, नहीं रिक्त स्ट्रिंग।
बॉर्न शेल में, के साथ:
var=value cmd
यदि cmd
एक अंतर्निहित (जैसे read
) है, तो समाप्त होने के बाद var
सेट रहता है । यह विशेष रूप से महत्वपूर्ण है क्योंकि बॉर्न शेल में, विस्तार करने के लिए ही नहीं, सब कुछ विभाजित करने के लिए उपयोग किया जाता है। इसके अलावा, यदि आप बॉर्न शेल में स्पेस कैरेक्टर को हटाते हैं, तो काम नहीं करता है।value
cmd
$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
, लेकिन अभी भी बहुत अधिक सहज है।