पायथन डिक्शनरी के समकक्ष क्या है लेकिन बैश (ओएस एक्स और लिनक्स में काम करना चाहिए)।
पायथन डिक्शनरी के समकक्ष क्या है लेकिन बैश (ओएस एक्स और लिनक्स में काम करना चाहिए)।
जवाबों:
बैश 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 में, आप इस वर्कअराउंड से बचकर पहली बार में एसोसिएटिव ऐरे का उपयोग कर सकते हैं।)
सारांश:
declare -A
साहचर्य सरणियों के लिए उपयोग करें ।declare
यदि आप अपग्रेड नहीं कर सकते तो विकल्प का उपयोग करें ।awk
इसके बजाय का उपयोग करने पर विचार करें और पूरी तरह से मुद्दे से बचें।4.x
और नहीं y
।
sudo port install bash
, उन लोगों के लिए (बुद्धिमानी से, IMHO) स्पष्ट रूप से प्रति-प्रक्रिया विशेषाधिकार वृद्धि के बिना सभी उपयोगकर्ताओं के लिए पथ में निर्देशिका बनाने के लिए तैयार नहीं है।
वहाँ पैरामीटर प्रतिस्थापन है, हालांकि यह संयुक्त राष्ट्र के रूप में अच्छी तरह से पीसी हो सकता है ... अप्रत्यक्ष की तरह।
#!/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 रास्ता बेशक बेहतर है, लेकिन अगर आपको हैक की जरूरत है ... केवल एक हैक करेगा। आप इसी तरह की तकनीकों के साथ सरणी / हैश खोज सकते हैं।
VALUE=${animal#*:}
उस मामले को बचाने के लिए ARRAY[$x]="caesar:come:see:conquer"
for animal in "${ARRAY[@]}"; do
यह वही है जो मैं यहाँ देख रहा था:
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" )
आप आगे चलकर 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`
फाइल सिस्टम एक ट्री स्ट्रक्चर है जिसे हैश मैप के रूप में इस्तेमाल किया जा सकता है। आपकी हैश तालिका एक अस्थायी निर्देशिका होगी, आपकी कुंजी फ़ाइल नाम होगी, और आपके मान फ़ाइल सामग्री होंगे। लाभ यह है कि यह विशाल हैशमैप को संभाल सकता है, और इसके लिए एक विशिष्ट शेल की आवश्यकता नहीं होती है।
hashtable=$(mktemp -d)
echo $value > $hashtable/$key
value=$(< $hashtable/$key)
बेशक, इसकी गति धीमी है, लेकिन धीमी नहीं है । मैंने SSD और btrfs के साथ अपनी मशीन पर इसका परीक्षण किया , और यह प्रति सेकंड लगभग 3000 तत्व पढ़ / लिखता है ।
mkdir -d
? (४.२ नहीं, उबंटू १४ पर। मैं इसका सहारा mkdir /run/shm/foo
mkdir /tmp/foo
mktemp -d
इसके बजाय मतलब था?
$value=$(< $hashtable/$key)
और value=$(< $hashtable/$key)
? धन्यवाद!
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
${var#start}
पाठ को हटा शुरू चर में संग्रहीत मूल्य की शुरुआत से वर ।
एक समाधान निर्मित बैश उपयोग करने पर विचार पढ़ने के रूप में एक 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
IFS=$'|' read -r first rest <<< "$fields"
मैं @ ललनाथ और अन्य लोगों से सहमत हूं कि साहचर्य सरणी बाश 4 के साथ जाने का तरीका है। यदि आप बैश 3 (OSX, पुराने डिस्ट्रोस जिसे आप अपडेट नहीं कर सकते हैं) से चिपके रहते हैं, तो आप एक्सप का उपयोग भी कर सकते हैं, जो हर जगह होना चाहिए, एक स्ट्रिंग और नियमित अभिव्यक्ति। मुझे यह विशेष रूप से पसंद है जब शब्दकोश बहुत बड़ा नहीं है।
अपने नक्शे को एक स्ट्रिंग के रूप में लिखें (विभाजक को नोट करें), 'शुरुआत और अंत में भी)
animals=",moo:cow,woof:dog,"
मान निकालने के लिए regex का उपयोग करें
get_animal {
echo "$(expr "$animals" : ".*,$1:\([^,]*\),.*")"
}
आइटम सूचीबद्ध करने के लिए स्ट्रिंग विभाजित करें
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
मुझे वास्तव में अल पी का जवाब पसंद आया, लेकिन अद्वितीयता सस्ते में लागू हुई, इसलिए मैंने इसे एक कदम आगे बढ़ाया - एक निर्देशिका का उपयोग करें। कुछ स्पष्ट सीमाएँ (निर्देशिका फ़ाइल सीमाएँ, अमान्य फ़ाइल नाम) हैं, लेकिन यह अधिकांश मामलों के लिए काम करना चाहिए।
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 () जोड़ना
दो चीजें, आप किसी भी कर्नेल 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
।
एक सहकर्मी ने सिर्फ इस धागे का उल्लेख किया है। मैंने स्वतंत्र रूप से हैश टेबलों को बैश के भीतर लागू किया है, और यह संस्करण 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
और दोस्तों में छोड़कर, हैश की आवश्यकता हो सकती है ।
बैश 4 से पहले बैश में साहचर्य सरणियों का उपयोग करने का कोई अच्छा तरीका नहीं है। आपकी सबसे अच्छी शर्त एक व्याख्या की गई भाषा का उपयोग करना है जो वास्तव में ऐसी चीजों के लिए समर्थन करती है, जैसे कि जाग। दूसरी ओर, बैश 4 उनका समर्थन करता है।
बाश 3 में कम अच्छे तरीकों के लिए , यहाँ मदद से एक संदर्भ है: http://mywiki.wooledge.org/BashFAQ/006
बैश 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[@])
मैं भी 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
मैं डायनेमिक वैरिएबल का उपयोग करके bash 3 में HashMaps बनाता हूं। मैंने समझाया कि मेरे उत्तर में यह कैसे काम करता है: शैल लिपियों में साहचर्य सरणियाँ
इसके अलावा आप शेल_मैप में एक नज़र डाल सकते हैं , जो बैश 3 में बनाया गया हैशपैम कार्यान्वयन है।