कैसे हैश में हैश टेबल को परिभाषित करने के लिए?


556

पायथन डिक्शनरी के समकक्ष क्या है लेकिन बैश (ओएस एक्स और लिनक्स में काम करना चाहिए)।


4
बैश एक अजगर / पर्ल स्क्रिप्ट चला ... यह इतना लचीला है!
e2-e4

ज़ोनश का उपयोग करने पर विचार करें (यह गीथब पर है)।
ओलिवर

जवाबों:


938

बैश ४

बैश 4 देशी इस सुविधा का समर्थन करता है। सुनिश्चित करें कि आपकी स्क्रिप्ट का हैशबैंग है #!/usr/bin/env bashया #!/bin/bashइसलिए आप उपयोग करना समाप्त नहीं करते हैं sh। सुनिश्चित करें कि आप या तो अपनी स्क्रिप्ट को सीधे निष्पादित कर रहे हैं, या scriptसाथ निष्पादित कर रहे हैं bash script। (वास्तव में बैश के साथ बैश स्क्रिप्ट पर अमल नहीं होता है, और वास्तव में भ्रमित हो जाएगा !)

आप एक सहयोगी सरणी की घोषणा करते हैं:

declare -A animals

आप इसे सामान्य सरणी असाइनमेंट ऑपरेटर का उपयोग करके तत्वों से भर सकते हैं। उदाहरण के लिए, यदि आप चाहते हैं animal[sound(key)] = animal(value):

animals=( ["moo"]="cow" ["woof"]="dog")

या उन्हें मर्ज करें:

declare -A animals=( ["moo"]="cow" ["woof"]="dog")

फिर उन्हें सामान्य सरणियों की तरह उपयोग करें। उपयोग

  • animals['key']='value' मूल्य निर्धारित करने के लिए

  • "${animals[@]}" मूल्यों का विस्तार करने के लिए

  • "${!animals[@]}"(नोटिस !) कुंजी का विस्तार करने के लिए

उन्हें उद्धृत करने के लिए मत भूलना:

echo "${animals[moo]}"
for sound in "${!animals[@]}"; do echo "$sound - ${animals[$sound]}"; done

बैश ३

बैश 4 से पहले, आपके पास सहयोगी सरणियाँ नहीं हैं। उनका अनुकरण करने के लिए उपयोग न करेंeval । बचें evalप्लेग की तरह है, क्योंकि यह है शेल पटकथा लेखन की प्लेग। सबसे महत्वपूर्ण कारण यह है कि evalआपके डेटा को निष्पादन योग्य कोड के रूप में माना जाता है (कई अन्य कारण भी हैं)।

सबसे पहले : 4 को अपग्रेड करने पर विचार करें। यह पूरी प्रक्रिया को आपके लिए बहुत आसान बना देगा।

यदि कोई कारण है जिसे आप अपग्रेड नहीं कर सकते हैं, declareतो एक अधिक सुरक्षित विकल्प है। यह बैश कोड जैसे डेटा का मूल्यांकन नहीं करता हैeval करता है, और जैसे कि मनमाने ढंग से कोड इंजेक्शन को इतनी आसानी से अनुमति नहीं देता है।

आइए अवधारणाओं को प्रस्तुत करके उत्तर तैयार करें:

पहला, अप्रत्यक्ष।

$ animals_moo=cow; sound=moo; i="animals_$sound"; echo "${!i}"
cow

दूसरी बात declare:

$ sound=moo; animal=cow; declare "animals_$sound=$animal"; echo "$animals_moo"
cow

उन्हें एक साथ लाओ:

# Set a value:
declare "array_$index=$value"

# Get a value:
arrayGet() { 
    local array=$1 index=$2
    local i="${array}_$index"
    printf '%s' "${!i}"
}

चलो इसका इस्तेमाल करते हैं:

$ sound=moo
$ animal=cow
$ declare "animals_$sound=$animal"
$ arrayGet animals "$sound"
cow

नोट: declareएक फ़ंक्शन में नहीं डाला जा सकता है। declareबैश फ़ंक्शन के अंदर का कोई भी उपयोग उस चर को उस फ़ंक्शन के दायरे में स्थानीय बनाता है , जिसका अर्थ है कि हम इसके साथ वैश्विक सरणियों को एक्सेस या संशोधित नहीं कर सकते हैं। (बैश 4 में आप ग्लोबल वैरिएबल्स को घोषित करने के लिए डिक्लेयर -g का उपयोग कर सकते हैं - लेकिन बैश 4 में, आप इस वर्कअराउंड से बचकर पहली बार में एसोसिएटिव ऐरे का उपयोग कर सकते हैं।)

सारांश:

  • 4 बैश करने के लिए अपग्रेड करें और declare -Aसाहचर्य सरणियों के लिए उपयोग करें ।
  • declareयदि आप अपग्रेड नहीं कर सकते तो विकल्प का उपयोग करें ।
  • awkइसके बजाय का उपयोग करने पर विचार करें और पूरी तरह से मुद्दे से बचें।

1
@ रीचर्ड: संभवतः, आप वास्तव में बैश का उपयोग नहीं कर रहे हैं। क्या आपका हैशबैंग बैश के बजाय है, या आप अन्यथा अपने कोड को श के साथ लगा रहे हैं? अपने ऐलान से पहले इसे सही रखने का प्रयास करें: "$ BASH_VERSION $ POSIXLY_CORRECT" की प्रतिध्वनि करें, यह आउटपुट होना चाहिए 4.xऔर नहीं y
लहनाथ

5
अपग्रेड नहीं किया जा सकता: बैश में स्क्रिप्ट लिखने का एकमात्र कारण पोर्टेबिलिटी "कहीं भी चलना" है। तो बैश की एक गैर-सार्वभौमिक विशेषता पर भरोसा करना इस दृष्टिकोण को नियंत्रित करता है। जो एक शर्म की बात है, क्योंकि अन्यथा यह मेरे लिए एक उत्कृष्ट समाधान होता!
स्टीव पिचर्स

3
यह शर्म की बात है कि ओएसएक्स बैश 3 को अभी भी डिफॉल्ट करता है क्योंकि यह बहुत सारे लोगों के लिए "डिफ़ॉल्ट" का प्रतिनिधित्व करता है। मुझे लगा कि शेलशॉक डरा हुआ हो सकता है कि उन्हें उस धक्का की जरूरत थी, लेकिन जाहिर तौर पर नहीं।
केन

13
@ken यह एक लाइसेंसिंग समस्या है। ओएसएक्स पर बैश नवीनतम गैर-जीपीएलवी 3 लाइसेंस प्राप्त बिल्ड पर अटका हुआ है।
लुननाथ

2
... या sudo port install bash, उन लोगों के लिए (बुद्धिमानी से, IMHO) स्पष्ट रूप से प्रति-प्रक्रिया विशेषाधिकार वृद्धि के बिना सभी उपयोगकर्ताओं के लिए पथ में निर्देशिका बनाने के लिए तैयार नहीं है।
चार्ल्स डफी

125

वहाँ पैरामीटर प्रतिस्थापन है, हालांकि यह संयुक्त राष्ट्र के रूप में अच्छी तरह से पीसी हो सकता है ... अप्रत्यक्ष की तरह।

#!/bin/bash

# Array pretending to be a Pythonic dictionary
ARRAY=( "cow:moo"
        "dinosaur:roar"
        "bird:chirp"
        "bash:rock" )

for animal in "${ARRAY[@]}" ; do
    KEY="${animal%%:*}"
    VALUE="${animal##*:}"
    printf "%s likes to %s.\n" "$KEY" "$VALUE"
done

printf "%s is an extinct animal which likes to %s\n" "${ARRAY[1]%%:*}" "${ARRAY[1]##*:}"

BASH 4 रास्ता बेशक बेहतर है, लेकिन अगर आपको हैक की जरूरत है ... केवल एक हैक करेगा। आप इसी तरह की तकनीकों के साथ सरणी / हैश खोज सकते हैं।


5
मैं VALUE=${animal#*:}उस मामले को बचाने के लिए ARRAY[$x]="caesar:come:see:conquer"
बदलूंगा

2
$ {ARRAY [@]} के आस-पास दोहरे उद्धरण चिह्नों को रखने के लिए भी उपयोगी है अगर वहाँ कुंजियों या मूल्यों में रिक्त स्थान हैं, जैसे किfor animal in "${ARRAY[@]}"; do
devguydavid

1
लेकिन दक्षता काफी गरीब नहीं है? मैं O (n * m) सोच रहा हूँ यदि आप उचित हैशमैप के साथ O (n) के बजाय कुंजियों की एक और सूची की तुलना करना चाहते हैं (एक ही कुंजी के लिए निरंतर समय की खोज, O (1))।
कोडमेनएक्स

1
यह विचार दक्षता के बारे में कम है, पर्ल, पाइथन या बैश में पृष्ठभूमि वाले लोगों के लिए समझने / पढ़ने-समझने की क्षमता के बारे में अधिक है। 4. आपको इसी तरह से लिखने की अनुमति देता है।
बुब्ऑनफ़ 15

1
@CoDEmanX: यह एक है हैक , एक चतुर और सुरुचिपूर्ण, लेकिन अभी भी अल्पविकसित वैकल्पिक हल मदद करने के लिए गरीब आत्माओं अभी भी बैश 3.x. के साथ 2007 में अटक आप इस तरह के एक सरल कोड में "उचित हैशमैप" या दक्षता के विचारों की उम्मीद नहीं कर सकते।
MestreLion

85

यह वही है जो मैं यहाँ देख रहा था:

declare -A hashmap
hashmap["key"]="value"
hashmap["key2"]="value2"
echo "${hashmap["key"]}"
for key in ${!hashmap[@]}; do echo $key; done
for value in ${hashmap[@]}; do echo $value; done
echo hashmap has ${#hashmap[@]} elements

इसने मेरे साथ काम नहीं किया था 4.1.5:

animals=( ["moo"]="cow" )

2
ध्यान दें, मान में रिक्त स्थान नहीं हो सकता है, अन्यथा आप एक बार में अधिक तत्वों को
जोड़ते हैं

6
हैशमैप के लिए अपवित्र ["कुंजी"] = "मूल्य" वाक्यविन्यास जो मैंने भी, अन्यथा शानदार स्वीकार किए गए उत्तर से गायब पाया।
थॉमसन

@ rubo77 कुंजी न तो, यह कई कुंजी जोड़ता है। इसे हल करने का कोई तरीका?
Xeverous

25

आप आगे चलकर hput () / hget () इंटरफ़ेस को संशोधित कर सकते हैं ताकि आपने हैश का नाम इस प्रकार रखा हो:

hput() {
    eval "$1""$2"='$3'
}

hget() {
    eval echo '${'"$1$2"'#hash}'
}

और फिर

hput capitals France Paris
hput capitals Netherlands Amsterdam
hput capitals Spain Madrid
echo `hget capitals France` and `hget capitals Netherlands` and `hget capitals Spain`

यह आपको अन्य मानचित्रों को परिभाषित करने देता है जो संघर्ष नहीं करते हैं (उदाहरण के लिए, 'rcapitals' जो देश की राजधानी द्वारा खोज करता है)। लेकिन, किसी भी तरह, मुझे लगता है कि आप पाएंगे कि यह सब बहुत भयानक है, प्रदर्शन-वार।

यदि आप वास्तव में फास्ट हैश लुकिंग चाहते हैं, तो एक भयानक, भयानक हैक है जो वास्तव में वास्तव में अच्छी तरह से काम करता है। यह है: एक अस्थायी फ़ाइल के लिए अपनी कुंजी / मान लिखें, एक-प्रति पंक्ति, फिर उन्हें निकालने के लिए 'grep "^ $ कुंजी" का उपयोग करें, कटौती या awk या sed के साथ पाइप का उपयोग करके या जो भी मान पुनः प्राप्त करने के लिए।

जैसा कि मैंने कहा, यह भयानक लगता है, और ऐसा लगता है कि यह धीमा होना चाहिए और सभी प्रकार के अनावश्यक आईओ करना चाहिए, लेकिन व्यवहार में यह बहुत तेज़ है (डिस्क कैश कमाल है, यह नहीं है?), यहां तक ​​कि बहुत बड़े हैश के लिए भी। टेबल। आपको अपने आप में मुख्य विशिष्टता को लागू करना होगा, आदि भले ही आपके पास केवल कुछ सौ प्रविष्टियाँ हों, आउटपुट फ़ाइल / grep कॉम्बो मेरे लिए कई गुना अधिक तेज - कई गुना तेज होने वाला है। यह कम मेमोरी भी खाती है।

यहाँ यह करने का एक तरीका है:

hinit() {
    rm -f /tmp/hashmap.$1
}

hput() {
    echo "$2 $3" >> /tmp/hashmap.$1
}

hget() {
    grep "^$2 " /tmp/hashmap.$1 | awk '{ print $2 };'
}

hinit capitals
hput capitals France Paris
hput capitals Netherlands Amsterdam
hput capitals Spain Madrid

echo `hget capitals France` and `hget capitals Netherlands` and `hget capitals Spain`

1
महान! तुम भी इसे पुनरावृत्त कर सकते हैं: मैं में $ के लिए (compgen- एक चर capitols); do hget "$ i" "किया गया
zhaorufei

22

बस फ़ाइल सिस्टम का उपयोग करें

फाइल सिस्टम एक ट्री स्ट्रक्चर है जिसे हैश मैप के रूप में इस्तेमाल किया जा सकता है। आपकी हैश तालिका एक अस्थायी निर्देशिका होगी, आपकी कुंजी फ़ाइल नाम होगी, और आपके मान फ़ाइल सामग्री होंगे। लाभ यह है कि यह विशाल हैशमैप को संभाल सकता है, और इसके लिए एक विशिष्ट शेल की आवश्यकता नहीं होती है।

हैशटेबल निर्माण

hashtable=$(mktemp -d)

एक तत्व जोड़ें

echo $value > $hashtable/$key

एक तत्व पढ़ें

value=$(< $hashtable/$key)

प्रदर्शन

बेशक, इसकी गति धीमी है, लेकिन धीमी नहीं है । मैंने SSD और btrfs के साथ अपनी मशीन पर इसका परीक्षण किया , और यह प्रति सेकंड लगभग 3000 तत्व पढ़ / लिखता है


1
बैश का कौन सा संस्करण समर्थन करता है mkdir -d? (४.२ नहीं, उबंटू १४ पर। मैं इसका सहारा mkdir /run/shm/foomkdir /tmp/foo
लूंगा

1
शायद mktemp -dइसके बजाय मतलब था?
रीड

2
जिज्ञासु के बीच अंतर क्या है $value=$(< $hashtable/$key)और value=$(< $hashtable/$key)? धन्यवाद!
हेलिन वांग

1
"मेरी मशीन पर इसका परीक्षण किया गया" यह आपके एसएसडी के माध्यम से एक छेद को जलाने का एक शानदार तरीका है। सभी लिनक्स डिस्ट्रोफ डिफ़ॉल्ट रूप से tmpfs का उपयोग नहीं करते हैं।
kirbyfan64sos

मैं लगभग 50000 हैश प्रोसेस कर रहा हूं। पर्ल और PHP इसे 1/2 सेकंड से कम उम्र के बाल करते हैं। 1 सेकंड और कुछ में नोड। FS विकल्प धीमा लगता है। हालांकि, क्या हम यह सुनिश्चित कर सकते हैं कि फाइलें केवल रैम में मौजूद हैं, किसी तरह?
रॉल्फ

14
hput () {
  eval hash"$1"='$2'
}

hget () {
  eval echo '${hash'"$1"'#hash}'
}
hput France Paris
hput Netherlands Amsterdam
hput Spain Madrid
echo `hget France` and `hget Netherlands` and `hget Spain`

$ sh hash.sh
Paris and Amsterdam and Madrid

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

@DigitalRoss आप बता सकते हैं कि eval इको '$ {हैश' "$ 1" "# हैश} ' में #hash का क्या उपयोग है । मेरे लिए यह एक टिप्पणी के रूप में मुझे लगता है अधिक नहीं तो वह। क्या # सुष का यहाँ कोई विशेष अर्थ है?
संजय

@Sanjay ${var#start}पाठ को हटा शुरू चर में संग्रहीत मूल्य की शुरुआत से वर
jpaugh

11

एक समाधान निर्मित बैश उपयोग करने पर विचार पढ़ने के रूप में एक UFW फ़ायरवॉल स्क्रिप्ट कि इस प्रकार से कोड स्निपेट के भीतर सचित्र। इस दृष्टिकोण को वांछित के रूप में कई सीमांकित फ़ील्ड सेट (केवल 2 नहीं) का उपयोग करने का लाभ है। हमने इस्तेमाल किया है | सीमांकित क्योंकि पोर्ट रेंज स्पेसर्स के लिए एक बृहदान्त्र की आवश्यकता हो सकती है, अर्थात 6001: 6010

#!/usr/bin/env bash

readonly connections=(       
                            '192.168.1.4/24|tcp|22'
                            '192.168.1.4/24|tcp|53'
                            '192.168.1.4/24|tcp|80'
                            '192.168.1.4/24|tcp|139'
                            '192.168.1.4/24|tcp|443'
                            '192.168.1.4/24|tcp|445'
                            '192.168.1.4/24|tcp|631'
                            '192.168.1.4/24|tcp|5901'
                            '192.168.1.4/24|tcp|6566'
)

function set_connections(){
    local range proto port
    for fields in ${connections[@]}
    do
            IFS=$'|' read -r range proto port <<< "$fields"
            ufw allow from "$range" proto "$proto" to any port "$port"
    done
}

set_connections

2
@CharlieMartin: पढ़ा जाना एक बहुत शक्तिशाली विशेषता है और कई बैश प्रोग्रामर द्वारा इसका उपयोग किया जाता है। यह लिस्प की तरह सूची प्रसंस्करण के कॉम्पैक्ट रूपों की अनुमति देता है । उदाहरण के लिए, उपर्युक्त उदाहरण में हम केवल पहला तत्व IFS=$'|' read -r first rest <<< "$fields"
छीन सकते हैं

6

मैं @ ललनाथ और अन्य लोगों से सहमत हूं कि साहचर्य सरणी बाश 4 के साथ जाने का तरीका है। यदि आप बैश 3 (OSX, पुराने डिस्ट्रोस जिसे आप अपडेट नहीं कर सकते हैं) से चिपके रहते हैं, तो आप एक्सप का उपयोग भी कर सकते हैं, जो हर जगह होना चाहिए, एक स्ट्रिंग और नियमित अभिव्यक्ति। मुझे यह विशेष रूप से पसंद है जब शब्दकोश बहुत बड़ा नहीं है।

  1. 2 विभाजक चुनें जिन्हें आप कुंजियों और मूल्यों में उपयोग नहीं करेंगे (जैसे ',' और ':')
  2. अपने नक्शे को एक स्ट्रिंग के रूप में लिखें (विभाजक को नोट करें), 'शुरुआत और अंत में भी)

    animals=",moo:cow,woof:dog,"
  3. मान निकालने के लिए regex का उपयोग करें

    get_animal {
        echo "$(expr "$animals" : ".*,$1:\([^,]*\),.*")"
    }
  4. आइटम सूचीबद्ध करने के लिए स्ट्रिंग विभाजित करें

    get_animal_items {
        arr=$(echo "${animals:1:${#animals}-2}" | tr "," "\n")
        for i in $arr
        do
            value="${i##*:}"
            key="${i%%:*}"
            echo "${value} likes to $key"
        done
    }

अब आप इसका उपयोग कर सकते हैं:

$ animal = get_animal "moo"
cow
$ get_animal_items
cow likes to moo
dog likes to woof

5

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

hinit() {
    rm -rf /tmp/hashmap.$1
    mkdir -p /tmp/hashmap.$1
}

hput() {
    printf "$3" > /tmp/hashmap.$1/$2
}

hget() {
    cat /tmp/hashmap.$1/$2
}

hkeys() {
    ls -1 /tmp/hashmap.$1
}

hdestroy() {
    rm -rf /tmp/hashmap.$1
}

hinit ids

for (( i = 0; i < 10000; i++ )); do
    hput ids "key$i" "value$i"
done

for (( i = 0; i < 10000; i++ )); do
    printf '%s\n' $(hget ids "key$i") > /dev/null
done

hdestroy ids

यह मेरे परीक्षणों में भी थोड़ा बेहतर प्रदर्शन करता है।

$ time bash hash.sh 
real    0m46.500s
user    0m16.767s
sys     0m51.473s

$ time bash dirhash.sh 
real    0m35.875s
user    0m8.002s
sys     0m24.666s

बस सोचा था कि मैं पिच करूँगा, चीयर्स!

संपादित करें: hdestroy () जोड़ना


3

दो चीजें, आप किसी भी कर्नेल 2.6 में / tmp के बजाय मेमोरी का उपयोग कर सकते हैं / dev / shm (Redhat) का उपयोग करके अन्य डिस्ट्रोस अलग-अलग हो सकते हैं। इसके अलावा पठन को निम्नानुसार उपयोग करके फिर से लागू किया जा सकता है:

function hget {

  while read key idx
  do
    if [ $key = $2 ]
    then
      echo $idx
      return
    fi
  done < /dev/shm/hashmap.$1
}

यह मानकर कि सभी कुंजियाँ अद्वितीय हैं, रिटर्न शॉर्ट सर्किट रीड लूप को बंद कर देता है और सभी प्रविष्टियों के माध्यम से पढ़ने से रोकता है। यदि आपके कार्यान्वयन में डुप्लिकेट कुंजियाँ हो सकती हैं, तो बस वापसी छोड़ दें। यह grep और awk दोनों को पढ़ने और धन्यवाद करने के खर्च को बचाता है। दोनों कार्यान्वयन के लिए / dev / shm का उपयोग करके अंतिम प्रविष्टि के लिए खोज करने वाले 3 प्रविष्टि हैश पर समय का उपयोग करके निम्नलिखित प्राप्त किया गया:

ग्रेप / Awk:

hget() {
    grep "^$2 " /dev/shm/hashmap.$1 | awk '{ print $2 };'
}

$ time echo $(hget FD oracle)
3

real    0m0.011s
user    0m0.002s
sys     0m0.013s

पढ़ें / गूंज:

$ time echo $(hget FD oracle)
3

real    0m0.004s
user    0m0.000s
sys     0m0.004s

कई आह्वान पर मैंने कभी कम नहीं देखा तो 50% सुधार हुआ। यह सब सिर के ऊपर कांटे के लिए जिम्मेदार ठहराया जा सकता है, के उपयोग के कारण /dev/shm


3

एक सहकर्मी ने सिर्फ इस धागे का उल्लेख किया है। मैंने स्वतंत्र रूप से हैश टेबलों को बैश के भीतर लागू किया है, और यह संस्करण 4 पर निर्भर नहीं है। मार्च 2010 में मेरे एक ब्लॉग पोस्ट से (कुछ उत्तरों से पहले ...) बैश में हैश टेबल्स का हकदार :

मैं पहले से इस्तेमाल किया cksumहैश को लेकिन जब से अनुवाद किया है जावा के स्ट्रिंग hashCode देशी बैश / zsh करने के लिए।

# Here's the hashing function
ht() {
  local h=0 i
  for (( i=0; i < ${#1}; i++ )); do
    let "h=( (h<<5) - h ) + $(printf %d \'${1:$i:1})"
    let "h |= h"
  done
  printf "$h"
}

# Example:

myhash[`ht foo bar`]="a value"
myhash[`ht baz baf`]="b value"

echo ${myhash[`ht baz baf`]} # "b value"
echo ${myhash[@]} # "a value b value" though perhaps reversed
echo ${#myhash[@]} # "2" - there are two values (note, zsh doesn't count right)

यह द्विदिश नहीं है, और अंतर्निहित तरीका बहुत बेहतर है, लेकिन न तो वास्तव में वैसे भी उपयोग किया जाना चाहिए। बैश त्वरित वन-ऑफ़ के लिए है, और इस तरह की चीजों में शायद ही कभी जटिलता की आवश्यकता होती है जो कि आपके ~/.bashrcऔर दोस्तों में छोड़कर, हैश की आवश्यकता हो सकती है ।


जवाब में लिंक डरावना है! यदि आप इसे क्लिक करते हैं, तो आप एक पुनर्निर्देशन पाश में फंस जाते हैं। कृपया अद्यतन करें।
रकीब

1
@MohammadRakibAmin - हाँ, मेरी वेबसाइट डाउन है और मुझे संदेह है कि मैं अपने ब्लॉग को फिर से जीवित करूँगा। मैंने उपरोक्त लिंक को एक संग्रहीत संस्करण में अपडेट किया है। आपकी रुचि के लिए धन्यवाद!
एडम काटज़

2

बैश 4 से पहले बैश में साहचर्य सरणियों का उपयोग करने का कोई अच्छा तरीका नहीं है। आपकी सबसे अच्छी शर्त एक व्याख्या की गई भाषा का उपयोग करना है जो वास्तव में ऐसी चीजों के लिए समर्थन करती है, जैसे कि जाग। दूसरी ओर, बैश 4 उनका समर्थन करता है।

बाश 3 में कम अच्छे तरीकों के लिए , यहाँ मदद से एक संदर्भ है: http://mywiki.wooledge.org/BashFAQ/006


2

बैश 3 समाधान:

कुछ उत्तरों को पढ़ने में मैंने एक त्वरित कार्य किया, जिसमें मैं वापस योगदान करना चाहूंगा जो दूसरों की मदद कर सकता है।

# Define a hash like this
MYHASH=("firstName:Milan"
        "lastName:Adamovsky")

# Function to get value by key
getHashKey()
 {
  declare -a hash=("${!1}")
  local key
  local lookup=$2

  for key in "${hash[@]}" ; do
   KEY=${key%%:*}
   VALUE=${key#*:}
   if [[ $KEY == $lookup ]]
   then
    echo $VALUE
   fi
  done
 }

# Function to get a list of all keys
getHashKeys()
 {
  declare -a hash=("${!1}")
  local KEY
  local VALUE
  local key
  local lookup=$2

  for key in "${hash[@]}" ; do
   KEY=${key%%:*}
   VALUE=${key#*:}
   keys+="${KEY} "
  done

  echo $keys
 }

# Here we want to get the value of 'lastName'
echo $(getHashKey MYHASH[@] "lastName")


# Here we want to get all keys
echo $(getHashKeys MYHASH[@])

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

0

मैं भी bash4 तरीका इस्तेमाल किया, लेकिन मुझे लगता है और बग परेशान।

मुझे गतिशील रूप से साहचर्य सरणी सामग्री को अपडेट करने की आवश्यकता थी इसलिए मैंने इस तरह से उपयोग किया:

for instanceId in $instanceList
do
   aws cloudwatch describe-alarms --output json --alarm-name-prefix $instanceId| jq '.["MetricAlarms"][].StateValue'| xargs | grep -E 'ALARM|INSUFFICIENT_DATA'
   [ $? -eq 0 ] && statusCheck+=([$instanceId]="checkKO") || statusCheck+=([$instanceId]="allCheckOk"
done

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

4.3.39 को कोसने में कोई समस्या नहीं है जहाँ पहले से मौजूद होने पर वास्तविक मूल्य को प्रतिस्थापित करने के लिए एक विद्यमान कुंजी को लागू करने का मतलब है।

मैंने इसे सिर्फ सफाई / स्टेटस चेक करने की घोषणा की है।

unset statusCheck; declare -A statusCheck

-1

मैं डायनेमिक वैरिएबल का उपयोग करके bash 3 में HashMaps बनाता हूं। मैंने समझाया कि मेरे उत्तर में यह कैसे काम करता है: शैल लिपियों में साहचर्य सरणियाँ

इसके अलावा आप शेल_मैप में एक नज़र डाल सकते हैं , जो बैश 3 में बनाया गया हैशपैम कार्यान्वयन है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.