शैल पटकथा इनपुट पुनर्निर्देशन विषमताएं

वोट
16

किसी को भी इस व्यवहार की व्याख्या कर सकते हैं? चल रहा है:

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

कुछ भी नहीं में परिणाम है, किया जा रहा है, जबकि ouput:

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

उम्मीद उत्पादन का उत्पादन:

hello
world

पाइप एक कदम में ऐसा नहीं करना चाहिए क्या test.file लिए पुनर्निर्देशन दूसरे उदाहरण में किया था? मैं दोनों पानी का छींटा और बैश के गोले के साथ एक ही कोड की कोशिश की और उन दोनों से समान व्यवहार हो गया।

05/08/2008 को 20:26
का स्रोत उपयोगकर्ता
अन्य भाषाओं में...                            


9 जवाब

वोट
11
#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

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

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

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

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

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

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

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

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

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

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

19/09/2008 को 03:20
का स्रोत उपयोगकर्ता

वोट
9

यह पहले से ही सही ढंग से जवाब दिया गया है, लेकिन समाधान अभी तक कहा नहीं किया गया है। 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

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

15/08/2008 को 16:52
का स्रोत उपयोगकर्ता

वोट
8

करने के लिए हाल ही में एक अतिरिक्त bashहै lastpipeविकल्प है, जो एक पाइपलाइन जब काम पर नियंत्रण कर दिया गया है, वर्तमान खोल, नहीं एक subshell में चलाने के लिए में पिछले आदेश अनुमति देता है।

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

वास्तव में उत्पादन होगा

hello
world
26/07/2012 को 13:10
का स्रोत उपयोगकर्ता

वोट
8
read var1 var2 < <(echo "hello world")
17/09/2008 को 01:17
का स्रोत उपयोगकर्ता

वोट
5

Allright, मैं यह पता लगा!

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

var1=$(echo "Hello")
echo var1

जो उम्मीद जवाब देता है। दुर्भाग्य से एकल चर के लिए यह केवल काम करता है, आप एक समय में कई निर्धारित नहीं कर सकते। एक समय में कई चर सेट करने के लिए आप या तो एक चर में पढ़ सकते हैं और इसे काटना कई चर में या कुछ इस तरह का उपयोग करना चाहिए:

set -- $(echo "Hello World")
var1="$1" var2="$2"
echo $var1
echo $var2

जब मैं स्वीकार करते हैं यह एक पाइप का उपयोग कर के रूप में के रूप में सुंदर नहीं है, यह काम करता है। बेशक आप ध्यान रखें कि पढ़ चर में फ़ाइलों से पढ़ने चाहिए था में रखने के लिए, तो यह मानक इनपुट से पढ़ने के एक छोटे से कठिन होना चाहिए बनाने चाहिए।

05/08/2008 को 21:09
का स्रोत उपयोगकर्ता

वोट
4

इस मुद्दे पर मेरे ले (बैश का प्रयोग करके):

read var1 var2 <<< "hello world"
echo $var1 $var2
04/03/2009 को 10:52
का स्रोत उपयोगकर्ता

वोट
4

पोस्ट ठीक उत्तर दिया गया है, लेकिन मैं एक विकल्प के एक लाइनर कि शायद कुछ काम का हो सकता है की पेशकश करना चाहते हैं।

गूंज से अंतरिक्ष अलग मान निर्दिष्ट (या उस बात के लिए stdout) चर शेल के लिए, आप खोल सरणियों उपयोग करने पर विचार कर सकते हैं:

$ var=( $( echo 'hello world' ) )
$ echo ${var[0]}
hello
$ echo ${var[1]}
world

इस उदाहरण वर में एक सरणी है और सामग्री निर्माण $ {var [सूचकांक]}, जहां सूचकांक सरणी सूचकांक (0 के साथ शुरू होता है) का उपयोग कर पहुँचा जा सकता है।

इस तरह आप के रूप में कई मापदंडों के रूप में आप प्रासंगिक सरणी सूचकांक करने के लिए आवंटित करना चाहते हो सकता है।

14/09/2008 को 18:00
का स्रोत उपयोगकर्ता

वोट
4

यह क्योंकि पाइप संस्करण एक subshell है, जो अपने स्थानीय अंतरिक्ष जो तब नष्ट हो जाता है जब subshell रास्ते में चर पढ़ता पैदा कर रही है है।

इस आदेश पर अमल

$ echo $$;cat | read a
10637

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

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)
05/08/2008 को 21:00
का स्रोत उपयोगकर्ता

वोट
3

प्रयत्न:

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

समस्या यह है, के रूप में कई लोगों ने कहा है, कि var1 और var2 एक subshell वातावरण है कि नष्ट हो जाता है जब कि subshell रास्ते में बनाया जाता है। ऊपर परिणाम जब तक subshell को नष्ट करने से बचा जाता है echo'd किया गया है। एक अन्य समाधान है:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
17/09/2008 को 03:15
का स्रोत उपयोगकर्ता

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more