linux - शैल इनपुट रीडायरेक्शन ओडियटिज़ स्क्रिप्ट




bash shell (6)

यह इसलिए है क्योंकि पाइप संस्करण एक सबशेल्ड का निर्माण कर रहा है, जो वैरिएबल को अपने स्थानीय स्थान में पढ़ता है, जो तब समाप्त हो जाता है जब सबशेम निकल जाता है

इस आदेश को निष्पादित करें

$ echo $$;cat | read a
10637

और चलने वाली प्रक्रियाओं को देखने के लिए pstree -p का उपयोग करें, आप अपने मुख्य शेल से लटके अतिरिक्त शेल देखेंगे।

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)

क्या कोई इस व्यवहार को समझा सकता है? चल रहा है:

#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

परिणाम कुछ भी नहीं होता है, जबकि:

#!/bin/sh
echo "hello world" > test.file
read var1 var2 < test.file
echo $var1
echo $var2

अपेक्षित आउटपुट उत्पन्न करता है:

hello
world

पाइप को एक कदम में नहीं करना चाहिए, जो कि परीक्षण के पुनर्निर्देशन का दूसरा उदाहरण है? मैंने डैश और बाश गोले दोनों के साथ एक ही कोड की कोशिश की और उन दोनों से समान व्यवहार मिला।


इससे पहले ही सही जवाब दिया गया है, लेकिन समाधान अभी तक नहीं बताया गया है। Ksh का प्रयोग करें, बाश नहीं। की तुलना करें:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | bash -s

सेवा मेरे:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | ksh -s
hello
world

इस तरह की छोटी छोटी समस्याओं के कारण केएसए एक बेहतर प्रोग्रामिंग शॉल है। (बाश मेरी राय में बेहतर इंटरैक्टिव शेल है।)


प्रयत्न:

echo "hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )

समस्या, जैसा कि बहुत से लोगों ने कहा है, यह है कि var1 और var2 को एक सबशेल्ड वातावरण में बनाया गया है जो उस सबशेल्ड से बाहर निकल जाता है। उपरोक्त उपशमन को नष्ट करने से बचा जाता है जब तक कि परिणाम को प्रतिध्वनित नहीं किया जाता है। एक अन्य समाधान है:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2

#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

कोई उत्पादन नहीं पैदा करता है क्योंकि पाइपलाइन एक सबशेल्ड के अंदर अपने प्रत्येक घटक चलाते हैं Subshells उन्हें साझा करने के बजाय, मूल शेल के चर की प्रतियां प्राप्त करते हैं। इसे इस्तेमाल करे:

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
(
    echo $foo
    foo="foo contents modified"
    echo $foo
)
echo $foo

कोष्ठक कोड के एक क्षेत्र को परिभाषित करता है जो एक सबशेल्ड में चला जाता है, और $ foo उनके मूल संस्करण को उनके अंदर संशोधित किए जाने के बाद बरकरार रखता है।

अब यह प्रयास करें:

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
{
    echo $foo
    foo="foo contents modified"
    echo $foo
}
echo $foo

ब्रेसिज़ पूरी तरह से ग्रुपिंग के लिए है, कोई सबशेल्ड नहीं बनाया गया है, और ब्रेज़ के अंदर संशोधित $ Foo ही उनके बाहर संशोधित $ Foo है।

अब यह प्रयास करें:

#!/bin/sh
echo "hello world" | {
    read var1 var2
    echo $var1
    echo $var2
}
echo $var1
echo $var2

ब्रेसिज़ के अंदर, पढ़ने के लिए निर्मित $ var1 और $ var2 को ठीक से बनाता है और आप देख सकते हैं कि वे प्रतिध्वनित हो जाते हैं ब्रेसिज़ के बाहर, वे किसी भी अधिक मौजूद नहीं हैं। ब्रेसिज़ के सभी कोड को एक सबशेल्ड में चलाया गया है क्योंकि यह एक पाइप लाइन का एक घटक है

आप ब्रेसिज़ के बीच की मनमाना मात्रा में कोड डाल सकते हैं, ताकि जब भी आपको खोल स्क्रिप्ट का एक ब्लॉक चलाने की जरूरत हो, जो कुछ और के आउटपुट को पार्स करता है, तो आप इस पाइपिंग-इन-एक-ब्लॉक निर्माण का उपयोग कर सकते हैं।


read var1 var2 < <(echo "hello world")

bash लिए हाल ही में एक अतिरिक्त विकल्प lastpipe विकल्प है, जो मौजूदा शेल में चलाने के लिए एक पाइप लाइन में आखिरी कमांड की अनुमति देता है, कोई lastpipe नहीं, जब नौकरी नियंत्रण निष्क्रिय हो जाता है

#!/bin/bash
set +m      # Deactiveate job control
shopt -s lastpipe
echo "hello world" | read var1 var2
echo $var1
echo $var2

वास्तव में आउटपुट होगा

hello
world




dash