2012-08-02 17 views
20

बैश में एक सहयोगी सरणी बनाने के लिए पूरी तरह से खोज करने के बाद, मैंने पाया कि declare -A array चाल करेगा। लेकिन समस्या यह है कि यह केवल बैश संस्करण 4 के लिए है और हमारे सिस्टम में सर्वर का बैश संस्करण 3.2.16 है।बैश में सहयोगी सरणी बनाएं 3

मैं बैश 3 में किसी प्रकार की एसोसिएटिव सरणी जैसी हैक कैसे प्राप्त कर सकता हूं? मूल्यों की तरह

ARG=array[key]; 

./script.sh ${ARG} 

संपादित एक स्क्रिप्ट को दे दिया जाएगा: मुझे पता है कि मैं awk में ऐसा कर सकते हैं, या अन्य उपकरण लेकिन सख्त बैश परिदृश्य मैं हल करने के लिए कोशिश कर रहा हूँ के लिए आवश्यक है।

+0

चूंकि बैश 3 में सामान्य सरणी होती है, तो आपको केवल उनके आधार पर सहयोगी सरणी लागू करनी होगी। लेकिन गंभीरता से, यह क्यों जरूरी होगा? –

+3

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

उत्तर

25

बैश 3 में कोई सहयोगी सरणी नहीं है, इसलिए आपको अपने उद्देश्य के लिए किसी अन्य भाषा सुविधा का उपयोग करना होगा। ध्यान दें कि बैश 4 के तहत भी, जो कोड आपने लिखा है वह वह नहीं करता है जो आप दावा करते हैं: ./script.sh ${ARG} एसोसिएटिव सरणी को बाल स्क्रिप्ट में पास नहीं करता है, क्योंकि ${ARG}ARG एक सहयोगी सरणी है जब कुछ भी नहीं फैलता है। आप एक सहयोगी सरणी को किसी बच्चे की प्रक्रिया में पास नहीं कर सकते हैं, आपको वैसे भी इसे एन्कोड करने की आवश्यकता है।

आपको मूल स्क्रिप्ट और बाल स्क्रिप्ट के बीच कुछ तर्क पारित प्रोटोकॉल को परिभाषित करने की आवश्यकता है। एक आम बात है key=value फॉर्म में तर्क पारित करना। यह मानता है कि वर्ण = कुंजी में प्रकट नहीं होता है।

आपको यह भी पता लगाना होगा कि मूल लिपि में और बाल स्क्रिप्ट में सहयोगी सरणी का प्रतिनिधित्व कैसे किया जाए। उन्हें एक ही प्रतिनिधित्व का उपयोग करने की आवश्यकता नहीं है।

एक सहयोगी सरणी का प्रतिनिधित्व करने के लिए एक आम विधि एक सामान्य नामकरण उपसर्ग के साथ प्रत्येक तत्व के लिए अलग-अलग चर का उपयोग करना है। इसके लिए आवश्यक है कि मुख्य नाम में केवल ASCII अक्षरों (किसी भी मामले का), अंक और अंडरस्कोर शामिल हों। उदाहरण के लिए, ${myarray[key]} के बजाय, ${myarray__key} लिखें। कुंजी रन टाइम पर निर्धारित किया जाता है, तो आप विस्तार का एक दौर पहले की जरूरत है: ${myarray[$key]} के बजाय,

n=myarray__${key}; echo ${!n} 

बारे में एक काम के लिए, printf -v का उपयोग करें। निर्दिष्ट मान का उपयोग करने के लिए %s प्रारूप printf पर ध्यान दें। printf -v "myarray__${key}" %s "$value" लिखें क्योंकि इससे प्रारूप के रूप में $value का इलाज होगा और प्रिंटफ % पर विस्तार होगा।

printf -v "myarray__${key}" %s "$value" 

आप key=value तर्क प्रतिनिधित्व के साथ एक बच्चे की प्रक्रिया के लिए इस तरह का प्रतिनिधित्व किया एक साहचर्य सरणी पारित करने के लिए की जरूरत है, तो आप ${!myarray__*} का उपयोग सभी चर जिसका नाम myarray__ साथ शुरू होता है से अधिक की गणना करने में कर सकते हैं।

args=() 
for k in ${!myarray__*}; do 
    n=$k 
    args+=("$k=${!n}") 
done 

बच्चे प्रक्रिया में, प्रपत्र key=value एक उपसर्ग के साथ चर को अलग करने के तर्कों कन्वर्ट करने के लिए:

for x; do 
    if [[ $x != *=* ]]; then echo 1>&2 "KEY=VALUE expected, but got $x"; exit 120; fi 
    printf -v "myarray__${x%%=*}" %s "${x#*=}" 
done 

वैसे, आपको लगता है कि यह है कि तुम क्या जरूरत है सुनिश्चित हैं? किसी अन्य बैश स्क्रिप्ट से बैश स्क्रिप्ट को कॉल करने के बजाय, आप इसके बजाय एक सबहेल में बाल स्क्रिप्ट को चलाने के लिए चाहते हैं। इस तरह यह माता-पिता के सभी चर से प्राप्त होगा।

+1

फ़ंक्शन में एक चर को स्थानीयकरण से बचने के लिए आप 'declare' के बजाय' printf -v' का उपयोग कर सकते हैं। इसे कॉल करने के बजाए बाल स्क्रिप्ट को सोर्स करना माता-पिता के सरणी और बच्चे को उपलब्ध अन्य चर बनाने का एक तरीका भी हो सकता है। –

+0

शानदार सामान! –

+0

मुझे समझ में नहीं आया कि आपने 'के लिए '' $ {! Myarray __ *} '' में बैकस्पेस क्यों लगाए हैं; करो 'यह एक आदेश नहीं है। –

2

आप कुंजी-मूल्य जोड़े को फ़ाइल में लिख सकते हैं और फिर कुंजी द्वारा grep लिख सकते हैं। आप की तरह

key=value 

एक पैटर्न का उपयोग करते हैं तो आप ^key= जो इस सुंदर सुरक्षित बनाता है के लिए egrep कर सकते हैं।

एक मूल्य "के ऊपर लिख" के लिए, बस फ़ाइल के अंत में नया मान संलग्न करें और tail -1 का उपयोग egrep

वैकल्पिक रूप से केवल अंतिम परिणाम देखने के, आप key=value का उपयोग कर एक सामान्य सरणी में इस जानकारी रख सकते हैं मूल्य खोजने के लिए सरणी के लिए मान और फिर सरणी पर इटरेटर के रूप में।

6

यहाँ बैश 3 में साहचर्य सरणियों और पुराने पैरामीटर विस्तार के प्रयोग पर एक और पोस्ट/स्पष्टीकरण है:
https://stackoverflow.com/a/4444841

गाइल्स 'विधि एक अच्छा if सीमांकक मुद्दों को पकड़ने के लिए बयान, स्वच्छ oddball इनपुट ... आदि है। उसका उपयोग करें।
http://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

अपने परिदृश्य में उपयोग करने के लिए [के रूप में कहा गया है: स्क्रिप्ट को भेजने]: स्क्रिप्ट 1: sending_array.sh

# A pretend Python dictionary with bash 3 
ARRAY=("cow:moo" 
     "dinosaur:roar" 
     "bird:chirp" 
     "bash:rock") 

bash ./receive_arr.sh "${ARRAY[@]}" 

स्क्रिप्ट 2

आप पैरामीटर विस्तार के साथ कुछ हद तक परिचित हैं, तो: receive_arr.sh

argAry1=("[email protected]") 

function process_arr() { 
    declare -a hash=("${!1}") 
    for animal in "${hash[@]}"; do 
     echo "Key: ${animal%%:*}" 
     echo "Value: ${animal#*:}" 
    done 
} 

process_arr argAry1[@] 

exit 0 

विधि 2, दूसरे पटकथा सोर्सिंग: स्क्रिप्ट 1: sending_array.sh

source ./receive_arr.sh 
# A pretend Python dictionary with bash 3 
ARRAY=("cow:moo" 
     "dinosaur:roar" 
     "bird:chirp" 
     "bash:rock") 

process_arr ARRAY[@] 

स्क्रिप्ट 2: receive_arr.sh

function process_arr() { 
    declare -a hash=("${!1}") 
    for animal in "${hash[@]}"; do 
     echo "Key: ${animal%%:*}" 
     echo "Value: ${animal#*:}" 
    done 
} 

संदर्भ:
Passing arrays as parameters in bash

2

आप को संभालने के लिए नहीं करना चाहते हैं बहुत सारे चर या कुंजी केवल अमान्य चर पहचानकर्ता हैं, और आपकी सरणी को 256 आइटम से कम होने की गारंटी है, तो आप फ़ंक्शन रिटर्न मानों का दुरुपयोग कर सकते हैं। इस समाधान को किसी भी सबहेल की आवश्यकता नहीं है क्योंकि मान एक परिवर्तनीय के रूप में आसानी से उपलब्ध है, न ही कोई पुनरावृत्ति जिससे प्रदर्शन चिल्लाता है। यह भी बहुत पठनीय है, लगभग बैश 4 संस्करण की तरह।

hash_index() { 
    case $1 in 
     'foo') return 0;; 
     'bar') return 1;; 
     'baz') return 2;; 
    esac 
} 

hash_vals=("foo_val" 
      "bar_val" 
      "baz_val"); 

hash_index "foo" 
echo ${hash_vals[$?]} 

अधिक जानकारी और वेरिएंट this answer

1

में यह हास्यास्पद आसान होने के लिए पता चला है:

यहाँ सबसे बुनियादी संस्करण है। मुझे एक बैश 4 स्क्रिप्ट को परिवर्तित करना पड़ा जो 3 को बाध्य करने के लिए एसोसिएटिव सरणी का एक गुच्छा इस्तेमाल करता था।इन दो सहायक कार्यों यह सब किया:

array_exp() { 
    exp=${@//[/__} 
    eval "${exp//]}" 
} 

array_clear() { 
    unset $(array_exp "echo \${!$1__*}") 
} 

मैं आश्चर्यचकित कि यह वास्तव में काम करता है, लेकिन है कि पार्टी की खासियत है। ईजी।

((all[ping_lo] += counts[ping_lo])) 

array_exp '((all[ping_lo] += counts[ping_lo]))' 

हो जाता है या यह प्रिंट बयान:

printf "%3d" ${counts[ping_lo]} >> $return 

array_exp 'printf "%3d" ${counts[ping_lo]}' >> $return 

केवल सिंटैक्स में परिवर्तन को साफ करते हो जाता है। यह:

counts=() 

array_clear counts 

हो जाता है और आप तैयार हैं। आप आसानी से array =exp को "=()" जैसे अभिव्यक्तियों को पहचानने के लिए बता सकते हैं और उन्हें array_clear अभिव्यक्ति के रूप में पुनः लिखकर संभाल सकते हैं, लेकिन मैं उपरोक्त दो कार्यों की सादगी पसंद करता हूं।

+0

यह अच्छा लग रहा है। मैं सोच रहा हूं कि बयान के साथ क्या करें: चलो '$ [$ i] ++', खासकर एकल उद्धरण। विचार/टिप्पणी? – Ray

+0

उपरोक्त आपके उत्तर में, array_exp() में eval कथन विफल रहता है जब मैं स्क्रिप्ट चलाता हूं; यह एक "खराब प्रतिस्थापन" के बारे में शिकायत कर रहा है – Ray

संबंधित मुद्दे