2012-08-13 16 views
6

में एक सरणी अनुक्रमणिका को असाइन करने में बाश परेशानी मैं इसे ksh में काम करने के लिए प्राप्त कर सकता हूं लेकिन बैश में नहीं जो वास्तव में मुझे पागल कर रहा है। उम्मीद है कि यह कुछ स्पष्ट है कि मैं देख रहा हूं।एक लूप

मुझे बाहरी कमांड चलाने की आवश्यकता है जहां आउटपुट की प्रत्येक पंक्ति सरणी अनुक्रमणिका में संग्रहीत की जाएगी।

यह सरलीकृत उदाहरण ऐसा लगता है कि यह लूप में सरणी को सही ढंग से सेट कर रहा है, हालांकि लूप ने उन सरणी असाइनमेंट को पूरा कर लिया है? ऐसा लगता है कि लूप को पूरी तरह से बाहरी खोल के रूप में माना जाता है?

junk.txt

this is a 
test to see 
if this works ok 

testa.sh

#!/bin/bash 

declare -i i=0 
declare -a array 

echo "Simple Test:" 
array[0]="hello" 
echo "array[0] = ${array[0]}" 

echo -e "\nLoop through junk.txt:" 
cat junk.txt | while read line 
do 
    array[i]="$line" 
    echo "array[$i] = ${array[i]}" 
    let i++ 
done 

echo -e "\nResults:" 
echo "  array[0] = ${array[0]}" 
echo " Total in array = ${#array[*]}" 
echo "The whole array:" 
echo ${array[@]} 

आउटपुट

Simple Test: 
array[0] = hello 

Loop through junk.txt: 
array[0] = this is a 
array[1] = test to see 
array[2] = if this works ok 

Results: 
     array[0] = hello 
Total in array = 1 
The whole array: 
hello 

इसलिए जब पाश में, हम सरणी [i] आवंटित और गूंज यह सत्यापित करता है। लेकिन लूप के बाद मैं सरणी [0] पर वापस आ गया हूं जिसमें कोई अन्य तत्व नहीं है "हैलो"।

बैश 3, 4 और विभिन्न प्लेटफॉर्म पर समान परिणाम।

उत्तर

7

क्योंकि आपका लूप पाइपलाइन में है, इसलिए लूप बॉडी में सभी परिवर्तनीय असाइनमेंट सबहेल के लिए स्थानीय होते हैं जिसमें लूप निष्पादित होता है। (मेरा मानना ​​है कि ksh एक subshell में आदेश नहीं चलता है, जिसके कारण आप bash में समस्या है।) के बजाय यह करें:

while read line 
do 
    array[i]="$line" 
    echo "array[$i] = ${array[i]}" 
    let i++ 
done < junk.txt 

शायद ही कभी, अगर कभी, आप पाइप एक को cat उपयोग करना चाहते हैं एकल फ़ाइल किसी अन्य कमांड पर; इसके बजाय इनपुट पुनर्निर्देशन का उपयोग करें।

अद्यतन:

while read line; do 
... 
done < <(command args ...) 

तो प्रक्रिया प्रतिस्थापन उपलब्ध नहीं है, आप के लिए उत्पादन करना होगा: जब से तुम एक कमांड और नहीं से एक फ़ाइल, एक और विकल्प (यदि उपलब्ध हो) चलाने की आवश्यकता प्रक्रिया प्रतिस्थापन है एक अस्थायी फ़ाइल और उस फ़ाइल से इनपुट पुनर्निर्देशित करें।

आप बैश 4.2 उपयोग कर रहे हैं या बाद में, आप अपने पाश से पहले इन दोनों आदेश पर अमल कर सकते हैं और मूल पाइप में-पाश काम करेंगे, के बाद से, जबकि पाश पिछले पाइप लाइन में आदेश है।

set +m # Turn off job control; it's probably already off in a non-interactive script 
shopt -s lastpipe 
cat junk.txt | while read line; do ...; done 

अद्यतन 2: यहाँ एक पाश कम user1596414 की टिप्पणी

array[0]=hello 
IFS=$'\n' array+=($(command)) 

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

+0

"मुझे बाहरी कमांड चलाने की आवश्यकता है जहां आउटपुट की प्रत्येक पंक्ति सरणी अनुक्रमणिका में संग्रहीत की जाएगी।" "बिल्ली" एक सरलीकृत उदाहरण था। मुझे एक कमांड चलाने और लूप में आउटपुट प्राप्त करने और user1596414

+0

कुछ विकल्पों के साथ अपडेट किया गया। आखिरी वाला (यदि आपका बैश का संस्करण पर्याप्त नया है) शायद वह वही है जिसे आप चाहते हैं। – chepner

+1

एक अस्थायी फ़ाइल +1 या बैश 4.2 (या बाद में) विकल्प काम करते हैं। सफेद रिक्त स्थान को संभालने के लिए आईएफएस का उपयोग करने वाला एक तीसरा विकल्प है और आउटपुट के माध्यम से पुन: प्रयास करने की आवश्यकता होने पर सरल सरणी असाइन के साथ जोड़ा जा सकता है। – user1596414