बैश में, एक पाइप के बाद पढ़ा जाने वाला मान सेट नहीं हो रहा है


22

संपादित करें: मूल शीर्षक "बैश में विफल रहता है" पढ़ा गया था

Ksh के साथ मैं पढ़ा जा रहा हूँ मानों को अलग करने के लिए एक सुविधाजनक तरीका के रूप में:

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 
2 1
$

लेकिन यह बाश में विफल रहता है:

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 

$

मुझे मैन पेज में एक कारण नहीं मिला कि यह विफल क्यों है, कोई विचार?


2
ग्रेग बैश एफएक्यू के पेज 024 में इस पर (कुछ अस्पष्ट रूप से) चर्चा की गई है ।
स्कॉट

जवाबों:


27

bash एक उप-प्रसंग में एक पाइप लाइन के दाहिने हाथ को चलाता है , इसलिए चर (जो ऐसा readकरता है) में परिवर्तन संरक्षित नहीं है - वे तब मरते हैं जब कमांड के अंत में, उप-भाग करता है।

इसके बजाय, आप प्रक्रिया प्रतिस्थापन का उपयोग कर सकते हैं :

$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1

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

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

read a b dump <<<"1 2 3 4 5"

मुझे लगता है कि वहाँ से यह अधिक है, लेकिन यह एक बेहतर विकल्प है अगर वहाँ नहीं है।


3
या भी read a b dump <<< '1 2 3 4 5'
कोरबा

आप सभी का शुक्रिया, btw मैंने नोट किया कि mksh (cygwin पर) बैश के समान कर रहा है।
इमैनुएल

@ मिचेल होमर अच्छी व्याख्या! मुझे एक और उदाहरण मिला, जो यह समझा सकता है कि पाइपलाइन में प्रत्येक कमांड स्वयं के उप-भाग में चलती है cat /etc/passwd | (read -r line ; echo $line):। लेकिन अगले echoकी $lineजो क्योंकि मूल्य सिर्फ बीच कोष्ठकों (subshell) अस्तित्व में किया गया था, स्क्रीन पर पाइप लाइन डाल कुछ भी नहीं में नहीं है। आशा है, यह किसी की मदद करता है।
Yurij Goncharuk

17

यह एक bashबग नहीं है जैसा POSIXकि दोनों bashऔर kshव्यवहारों को अनुमति देता है, जिसके कारण आप दुर्भाग्यपूर्ण विसंगति को देख रहे हैं।

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12

इसके अतिरिक्त, बहु-कमान पाइपलाइन की प्रत्येक कमांड एक उप-वातावरण में है; एक विस्तार के रूप में, हालांकि, एक पाइप लाइन में किसी भी या सभी आदेशों को मौजूदा वातावरण में निष्पादित किया जा सकता है। अन्य सभी आदेशों को वर्तमान शेल वातावरण में निष्पादित किया जाएगा।

हालाँकि, bash 4.2और नए के साथ , आप lastpipeअपेक्षित परिणाम प्राप्त करने के लिए गैर संवादात्मक स्क्रिप्ट में विकल्प सेट कर सकते हैं , उदाहरण के लिए:

#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a 
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a 

आउटपुट:

before:
after: 2 1

1
+1 आपको "लास्टपाइप" जानकारी के लिए धन्यवाद। देरी के लिए खेद है
इमैनुएल

1
इसके साथ समस्या lastpipeयह है कि यह अन्य गोले (जैसे डैश) में काम नहीं करता है। मूल रूप से सब-रनिंग के इस पोर्टेबल शॉर्ट को करने का कोई तरीका नहीं है, देखें stackoverflow.com/questions/36268479/…
aarcat

1
@anarcat यह सही है लेकिन यहाँ पूछा गया प्रश्न बैश के बारे में था।
jlliagre

@anarcat: यह भविष्य में बदल सकता है क्योंकि किसी अन्य कारण से POSIX को बदलने की इच्छा है (PIPE स्थिति) यहाँ देखें: unix.stackexchange.com/questions/476834/… अन्य गोले बदलना तुच्छ नहीं है, मुझे कई महीने लग गए आधुनिक ksh के तेज व्यवहार को लागू करने के लिए बॉर्न शेल (bosh) पर पार्सर और इंटरपीटर को फिर से लिखना।
विद्वान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.