इको या प्रिंट / देव / स्टडिन / देव / स्टडआउट / देव / स्टैडर


14

मैं / dev / stdin, / dev / stdout और / dev / stderr का मान छापना चाहता हूं।

यहाँ मेरी सरल स्क्रिप्ट है:

#!/bin/bash
echo your stdin is : $(</dev/stdin)
echo your stdout is : $(</dev/stdout)
echo your stderr is : $(</dev/stderr)

मैं निम्नलिखित पाइपों का उपयोग करता हूं:

[root@localhost home]# ls | ./myscript.sh
[root@localhost home]# testerr | ./myscript.sh

केवल $(</dev/stdin)काम करने के लिए लगता है, मैंने कुछ अन्य लोगों के सवालों पर भी पाया है जो लोगों का उपयोग करते हैं: "${1-/dev/stdin}"सफलता के बिना इसे आज़माया।

जवाबों:


30

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आउटपुट जो बाद में पढ़ा गया था।


2

stdoutऔर stderrआउटपुट हैं, आप उनसे नहीं पढ़ते हैं आप केवल उन्हें लिख सकते हैं। उदाहरण के लिए:

echo "this is stdout" >/dev/stdout
echo "this is stderr" >/dev/stderr

कार्यक्रम डिफ़ॉल्ट रूप से स्टडआउट के लिए लिखते हैं, इसलिए पहले वाले के बराबर है

echo "this is stdout"

और आप stderr को अन्य तरीकों से पुनर्निर्देशित कर सकते हैं जैसे कि

echo "this is stderr" 1>&2

1
लिनक्स पर, echo xऐसा नहीं है जैसे echo x > /dev/stdoutकि स्टडआउट पाइप में नहीं जाता है या कुछ वर्ण डिवाइस जैसे कि ट्टी डिवाइस। उदाहरण के लिए, यदि stdout एक नियमित फ़ाइल में जाता है, तो फ़ाइल echo x > /dev/stdoutको काट दिया जाएगा और इसकी सामग्री को वर्तमान stdout स्थिति x\nमें लिखने के बजाय बदल दिया जाएगा x\n
स्टीफन चेज़लस

@ माइकल-डैफिन> धन्यवाद, इसलिए अगर मैं stdout और stderr पढ़ना चाहता हूं तो मैं केवल बिल्ली का उपयोग कर सकता हूं? (चूंकि वे फाइलें हैं), उदाहरण के लिए मैं उपयोगकर्ता को हुई अंतिम त्रुटि दिखाना चाहता हूं echo this is your error $(cat /dev/stderr)?
उमर BISTAMI 13

@OmarBISTAMI आप से नहीं पढ़ सकते हैं stdoutऔर stderr, वे आउटपुट हैं।
Kusalananda

1

myscript.sh:

#!/bin/bash
filan -s

फिर भागो:

$ ./myscript.sh
    0 tty /dev/pts/1
    1 tty /dev/pts/1
    2 tty /dev/pts/1

$ ls | ./myscript.sh
    0 pipe 
    1 tty /dev/pts/1
    2 tty /dev/pts/1

$ ls | ./myscript.sh > out.txt
$ cat out.txt
    0 pipe 
    1 file /tmp/out.txt
    2 tty /dev/pts/1

आप शायद स्थापित करना होगा filanसाथ sudo apt install socatपहले।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.