stdin
, stdout
और , एक प्रक्रिया के क्रमशः फाइल डिस्क्रिप्टर 0, 1, और 2 से जुड़ी धाराएँstderr
हैं ।
एक टर्मिनल या टर्मिनल एमुलेटर में एक इंटरेक्टिव शेल के संकेत पर, वे सभी 3 फाइल डिस्क्रिप्टर एक ही ओपन फाइल डिस्क्रिप्शन का जिक्र करेंगे जो कि /dev/pts/0
रीड + राइट में टर्मिनल या छद्म टर्मिनल डिवाइस फाइल (कुछ इस तरह ) खोलने से प्राप्त होगा । मोड।
यदि उस इंटरैक्टिव शेल से, आप अपनी स्क्रिप्ट को बिना किसी पुनर्निर्देशन का उपयोग किए शुरू करते हैं, तो आपकी स्क्रिप्ट उन फ़ाइल विवरणकों को इनहेरिट करेगी।
लिनक्स पर, /dev/stdin
, /dev/stdout
, /dev/stderr
के सांकेतिक लिंक कर रहे हैं /proc/self/fd/0
, /proc/self/fd/1
, /proc/self/fd/2
क्रमशः, खुद को वास्तविक फ़ाइल है कि उन फ़ाइल वर्णनकर्ता पर खुला है करने के लिए विशेष सिमलिंक।
वे stdin, stdout, stderr नहीं हैं, वे ऐसी विशेष फाइलें हैं जो यह पहचानती हैं कि stdin, stdout, stderr क्या फाइलें जाती हैं (ध्यान दें कि यह लिनक्स की तुलना में अन्य प्रणालियों में भिन्न है जिनके पास विशेष फ़ाइलें हैं)।
स्टडिन से कुछ पढ़ने का अर्थ है फ़ाइल डिस्क्रिप्टर 0 से पढ़ना (जो कि संदर्भित फ़ाइल के भीतर कहीं इंगित करेगा /dev/stdin
)।
लेकिन $(</dev/stdin)
, शेल स्टड से नहीं पढ़ रहा है, यह उसी फाइल पर पढ़ने के लिए एक नया फाइल डिस्क्रिप्टर खोलता है, जो स्टड पर खुला होता है (इसलिए फाइल की शुरुआत से रीडिंग होती है, जहां स्टड वर्तमान में इंगित करता है)।
पठन + लेखन मोड में खुले टर्मिनल उपकरणों के विशेष मामले को छोड़कर, स्टडआउट और स्टादर आमतौर पर पढ़ने के लिए खुले नहीं होते हैं। उनका मतलब उन धाराओं से है जो आप लिखते हैं । इसलिए फ़ाइल डिस्क्रिप्टर 1 से पढ़ना आम तौर पर काम नहीं करेगा। लिनक्स पर, खोलने /dev/stdout
या /dev/stderr
पढ़ने के लिए (के रूप में $(</dev/stdout)
) काम करेगा और आपको उस फ़ाइल से पढ़ने देगा जहाँ stdout जाता है (और अगर stdout एक पाइप था, जो पाइप के दूसरे छोर से पढ़ेगा, और अगर यह एक सॉकेट था , यह विफल होगा क्योंकि आप सॉकेट नहीं खोल सकते हैं )।
एक टर्मिनल में एक इंटरेक्टिव शेल के संकेत पर पुनर्निर्देशन के बिना चलाए जाने वाले स्क्रिप्ट के हमारे मामले में, / dev / stdin, / dev / stdout और / dev / stderr के सभी / dev / pts / x टर्मिनल डिवाइस फ़ाइल होगी।
उन विशेष फ़ाइलों से पढ़ना, जो टर्मिनल द्वारा भेजा जाता है (जो आप कीबोर्ड पर टाइप करते हैं) देता है। उन्हें लिखने से पाठ टर्मिनल पर (प्रदर्शन के लिए) भेजा जाएगा।
echo $(</dev/stdin)
echo $(</dev/stderr)
एक ही हो जाएगा। विस्तार करने के लिए $(</dev/stdin)
, शेल उस / dev / pts / 0 को खोलेगा और पढ़ेगा जो आप टाइप करते हैं जब तक कि आप ^D
एक खाली लाइन पर नहीं दबाते । फिर वे विस्तार को पास करेंगे (जो आपने अनुगामी newlines से छीन लिया और विभाजित + ग्लोब के अधीन है) echo
जो तब इसे स्टडआउट (प्रदर्शन के लिए) पर आउटपुट करेगा।
हालाँकि इसमें:
echo $(</dev/stdout)
में bash
( और bash
केवल ), यह है कि अंदर महसूस करने के लिए महत्वपूर्ण है $(...)
, stdout पुनः निर्देशित किया गया है। यह अब एक पाइप है। के मामले में bash
, एक बाल खोल प्रक्रिया फ़ाइल (यहां /dev/stdout
) की सामग्री को पढ़ रही है और इसे पाइप पर लिख रही है, जबकि माता-पिता विस्तार करने के लिए दूसरे छोर से पढ़ते हैं।
इस मामले में जब वह बच्चा बैश प्रक्रिया खोलता है /dev/stdout
, तो यह वास्तव में पाइप के रीडिंग एंड को खोल रहा है। इससे कुछ नहीं होगा, यह एक गतिरोध की स्थिति है।
यदि आप स्क्रिप्ट स्टडआउट द्वारा बताई गई फ़ाइल से पढ़ना चाहते हैं, तो आप इसके साथ काम करेंगे:
{ echo content of file on stdout: "$(</dev/fd/3)"; } 3<&1
यह fd 3 पर fd 1 को डुप्लिकेट करेगा, इसलिए / dev / fd / 3 एक ही फ़ाइल को / dev / stdout के रूप में इंगित करेगा।
एक स्क्रिप्ट के साथ:
#! /bin/bash -
printf 'content of file on stdin: %s\n' "$(</dev/stdin)"
{ printf 'content of file on stdout: %s\n' "$(</dev/fd/3)"; } 3<&1
printf 'content of file on stderr: %s\n' "$(</dev/stderr)"
जब के रूप में चलाने:
echo bar > err
echo foo | myscript > out 2>> err
आप out
बाद में देखेंगे :
content of file on stdin: foo
content of file on stdout: content of file on stdin: foo
content of file on stderr: bar
तो के रूप में से पढ़ने के लिए विरोध किया /dev/stdin
, /dev/stdout
, /dev/stderr
, आप stdin, stdout और stderr (जो भी कम मतलब होगा) से पढ़ने के लिए चाहते थे, तुम क्या चाहते हैं:
#! /bin/sh -
printf 'what I read from stdin: %s\n' "$(cat)"
{ printf 'what I read from stdout: %s\n' "$(cat <&3)"; } 3<&1
printf 'what I read from stderr: %s\n' "$(cat <&2)"
यदि आपने वह दूसरी स्क्रिप्ट फिर से शुरू की:
echo bar > err
echo foo | myscript > out 2>> err
आप इसमें देखेंगे out
:
what I read from stdin: foo
what I read from stdout:
what I read from stderr:
और इसमें err
:
bar
cat: -: Bad file descriptor
cat: -: Bad file descriptor
Stdout और stderr के लिए, cat
विफल रहता है क्योंकि फ़ाइल विवरणक केवल लिखने के लिए खुले थे , पढ़ना नहीं, का विस्तार $(cat <&3)
और $(cat <&2)
खाली है।
यदि आप इसे कहते हैं:
echo out > out
echo err > err
echo foo | myscript 1<> out 2<> err
(जहां <>
ट्रंकेशन के बिना रीड + राइट मोड में खुलता है), आप इसमें देखेंगे out
:
what I read from stdin: foo
what I read from stdout:
what I read from stderr: err
और इसमें err
:
err
आप देखेंगे कि कुछ भी नहीं stdout से पढ़ा था, क्योंकि पिछले printf
की सामग्री ओवरराइट किया था out
के साथ what I read from stdin: foo\n
और उस फ़ाइल के तुरंत बाद ही भीतर stdout स्थिति छोड़ दिया है। यदि आपने out
किसी बड़े पाठ के साथ प्राइम किया था , जैसे:
echo 'This is longer than "what I read from stdin": foo' > out
तो आप में मिल जाएगा out
:
what I read from stdin: foo
read from stdin": foo
what I read from stdout: read from stdin": foo
what I read from stderr: err
देखें कि कैसे $(cat <&3)
पढ़ा है कि पहले के बाद क्या बचा था printf
और ऐसा करने से भी स्टडआउट की स्थिति अतीत में बदल गई ताकि अगले printf
आउटपुट जो बाद में पढ़ा गया था।
echo x
ऐसा नहीं है जैसेecho x > /dev/stdout
कि स्टडआउट पाइप में नहीं जाता है या कुछ वर्ण डिवाइस जैसे कि ट्टी डिवाइस। उदाहरण के लिए, यदि stdout एक नियमित फ़ाइल में जाता है, तो फ़ाइलecho x > /dev/stdout
को काट दिया जाएगा और इसकी सामग्री को वर्तमान stdout स्थितिx\n
में लिखने के बजाय बदल दिया जाएगाx\n
।