2012-06-24 14 views
15

मैं यह कोड कैसे काम कर सकता हूं?अप्रत्यक्ष संदर्भ का उपयोग कर सरणी को फिर से कैसे करें?

#!/bin/bash 
ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE) 
for FRUIT in ${!ARRAYNAME[@]} 
do 
    echo ${FRUIT} 
done 

इस कोड:

echo ${!ARRAYNAME[0]} 

प्रिंटों सेब। मैं कुछ ऐसा करने की कोशिश कर रहा हूं लेकिन सरणी पर फिर से शुरू करने के लिए "[@]" के साथ।

अग्रिम धन्यवाद,

+4

कृपया देखें [BashFAQ/006] (http://mywiki.wooledge.org/BashFAQ/006)। –

उत्तर

18

${!ARRAYNAME[@]} का अर्थ है "ARRAYNAME के सूचकांकों"। जैसा कि में बताया गया है ARRAYNAME सेट है, लेकिन एक स्ट्रिंग के रूप में, कोई सरणी नहीं है, यह 0 देता है।

यहां eval का उपयोग कर एक समाधान है।

#!/usr/bin/env bash 

ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE) 

eval array=\(\${${ARRAYNAME}[@]} \) 

for fruit in "${array[@]}"; do 
    echo ${fruit} 
done 

क्या आप मूल रूप से करने के लिए कोशिश कर रहे थे एक Indirect Reference बनाने था। इन्हें बैश संस्करण 2 में पेश किया गया था और शैल में प्रतिबिंब-जैसे व्यवहार को प्राप्त करने का प्रयास करते समय eval की आवश्यकता को बड़े पैमाने पर बदलने के लिए किया गया था।

आप जब सरणियों के साथ अप्रत्यक्ष संदर्भ का उपयोग कर चर नाम पर अपने अनुमान में [@] शामिल है क्या करना है:

#!/usr/bin/env bash 

ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE) 

array="${ARRAYNAME}[@]" 
for fruit in "${!array}"; do 
    echo $fruit 
done 

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

+0

टिम: उत्तर का आपका दूसरा भाग उपयोगी नहीं है, क्योंकि ARRAYNAME मेरी स्क्रिप्ट का इनपुट पैरामीटर है। लेकिन आपका पहला समाधान मुझे एक और अधिक सुरुचिपूर्ण समाधान खोजने देता है: ARRAY = $ {! ARRAYNAME}; $ {ARRAY [@]} में फल के लिए ... धन्यवाद – Neuquino

+0

@Neuquino मेरा संपादित उत्तर देखें। आपको बस इतना करना है कि आपके इनपुट चर के अंत में '[@] 'को संयोजित करें। –

+2

@Neuquino यदि ARRAYNAME आपकी स्क्रिप्ट के लिए एक इनपुट पैरामीटर है तो आप कुछ गलत कर रहे हैं। परिवर्तनीय नामों के साथ उपयोगकर्ता इनपुट मिश्रण करने के शून्य कारण हैं। इस मामले में (अप्रत्यक्ष विस्तार के साथ संयुक्त), यह मनमाने ढंग से कोड इंजेक्शन की अनुमति देता है। इन तकनीकों का एकमात्र वैध कारण कार्यों में उपयोग के लिए है, कभी भी वैश्विक दायरे में नहीं और कभी भी उपयोगकर्ता इनपुट के साथ संयुक्त नहीं होता है। – ormaaj

0

मैं बस एक और उपयोगी उपयोग-केस जोड़ना चाहता था। मैं सरल ओपी प्रश्न के बावजूद एक अलग करने के लिए एक समाधान के लिए वेब, लेकिन समस्या से जूझ रहे

ARRAYNAME=(FRUITS VEG) 
FRUITS=(APPLE BANANA ORANGE) 
VEG=(CARROT CELERY CUCUMBER) 
for I in "${ARRAYNAME[@]}" 
do 
    array="${I}[@]" 
    for fruit in "${!array}"; do 
     echo $fruit 
    done 
done 
+0

'array =" $ {I} [@] "' tmp = $ arrayname [@] 'से बिल्कुल ठीक है! कोई सुधार नहीं है! –

0

खोज रहा था, ये उत्तर सबसे आम, वास्तविक उपयोग-मामले के लिए स्केल नहीं करेगा, यानी, सरणी तत्वों खाली स्थान के युक्त या वाइल्डकार्ड जिन्हें अभी तक फ़ाइल नामों में विस्तारित नहीं किया जाना चाहिए।

FRUITS=(APPLE BANANA ORANGE 'not broken' '*.h') 
ARRAYNAME=FRUITS 
eval ARRAY=\(\${$ARRAYNAME[@]}\) 

$ echo "${ARRAY[4]}" 
broken 
$ echo "${ARRAY[5]}" 
config.h 
$ 

यह काम करता है:

FRUITS=(APPLE BANANA ORANGE 'not broken' '*.h') 
ARRAYNAME=FRUITS 
eval ARRAY="(\"\${$ARRAYNAME[@]}\")" 

$ echo "${ARRAY[3]}" 
not broken 
$ echo "${ARRAY[4]}" 
*.h 
$ 

बस के रूप में आप "[email protected]" नहीं [email protected] का उपयोग कर की आदत में मिलना चाहिए, हमेशा सरणी विस्तार के लिए () अंदर बोली, जब तक आप फ़ाइल नाम विस्तार चाहते हैं या जानते हैं कि कोई संभावना नहीं है सफेद जगह वाले सरणी तत्वों का।

यह करें: X=("${Y[@]}")

नहीं इस: X=(${Y[@]})

8

यहाँ eval के बिना यह करने के लिए एक तरीका है।

बैश चाल # 2 यहाँ वर्णित देखें: http://mywiki.wooledge.org/BashFAQ/006

बैश 3 और ऊपर में काम करने लगता है।

#!/bin/bash 

ARRAYNAME='FRUITS' 
tmp=$ARRAYNAME[@] 
FRUITS=(APPLE BANANA ORANGE "STAR FRUIT") 
for FRUIT in "${!tmp}" 
do 
    echo "${FRUIT}" 
done 

यहाँ एक और अधिक यथार्थवादी कैसे एक समारोह के संदर्भ द्वारा एक सरणी पारित करने के लिए दिखा उदाहरण है:

pretty_print_array() { 
    local arrayname=$1 
    local tmp=$arrayname[@] 
    local array=("${!tmp}") 
    local FS=', ' # Field seperator 
    local var 
    # Print each element enclosed in quotes and separated by $FS 
    printf -v var "\"%s\"$FS" "${array[@]}" 
    # Chop trailing $FS 
    var=${var%$FS} 
    echo "$arrayname=($var)" 
} 
FRUITS=(APPLE BANANA ORANGE "STAR FRUIT") 
pretty_print_array FRUITS 
# prints FRUITS=("APPLE", "BANANA", "ORANGE", "STAR FRUIT") 
+0

बिना किसी अप्रत्यक्ष सरणी के आकार को प्राप्त करने के किसी भी तरीके से? –

0

eval कोड युक्त सरणी तत्वों को निष्पादित करता है, भले ही वे होते हैं, उदाहरण के लिए, आदेश प्रतिस्थापन। यह उन में बैश मेटाएक्टेक्टरों की व्याख्या करके सरणी तत्वों को भी बदलता है।

एकल उपकरण कि इन समस्याओं से बचा जाता है एक संदर्भ है:

#!/bin/bash 
declare -n ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE "BITTER LEMON") 
for FRUIT in "${ARRAYNAME[@]}" 
do 
    echo "${FRUIT}" 
done