পাইথন অভিধানের সমতুল্য তবে বাশে (ওএস এক্স এবং লিনাক্স জুড়ে কাজ করা উচিত)।
পাইথন অভিধানের সমতুল্য তবে বাশে (ওএস এক্স এবং লিনাক্স জুড়ে কাজ করা উচিত)।
উত্তর:
বাশ 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
ব্যাশ ফাংশনের অভ্যন্তরের যেকোন ব্যবহারের ফলে ভেরিয়েবলটি এটি স্থানীয়ভাবে তৈরি করে turns ফাংশনটি, যার অর্থ আমরা এটির সাথে বৈশ্বিক অ্যারে অ্যাক্সেস বা সংশোধন করতে পারি না। (ব্যাশ 4 এ আপনি ঘোষিত -g ব্যবহার করতে পারেন বৈশ্বিক ভেরিয়েবলগুলি ডিক্লেয়ার করতে - তবে ব্যাশ 4 এ, আপনি প্রথমে এসোসিয়েটিভ অ্যারেগুলি ব্যবহার করতে পারেন, এই কাজটি এড়িয়ে গিয়ে))
সারসংক্ষেপ:
declare -A
সহযোগী অ্যারেগুলির জন্য ব্যবহার করুন ।declare
আপনি আপগ্রেড করতে না পারলে বিকল্পটি ব্যবহার করুন ।awk
পরিবর্তে ব্যবহার বিবেচনা করুন এবং বিষয়টি পুরোপুরি এড়িয়ে চলুন।4.x
এবং হবে না y
।
sudo port install bash
, যারা (বুদ্ধিমানের সাথে, আইএমএইচও) সমস্ত ব্যবহারকারীদের জন্য প্রসেস-প্রসেসের সুবিধাযুক্ততা ছাড়াই লেখার জন্য PATH- এ ডিরেক্টরি তৈরি করতে রাজি নন।
প্যারামিটারের বিকল্প রয়েছে, যদিও এটি আন-পিসিও হতে পারে ... ইন্ডিরিশনের মতো।
#!/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]##*:}"
বেস 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
এটি আমার পক্ষে বাশ ৪.১.৫ নিয়ে কাজ করে নি:
animals=( ["moo"]="cow" )
আপনি hp () / 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`
এটি আপনাকে অন্যান্য মানচিত্র সংজ্ঞায়িত করতে দেয় যা দ্বন্দ্ব নয় (উদাহরণস্বরূপ, 'আরসি ক্যাপিটালস' যা রাজধানী শহর দ্বারা দেশ অনুসন্ধান করে)। তবে, যেভাবেই হোক না কেন, আমি মনে করি আপনি এটি দেখতে পাবেন যে এটি খুব ভয়ঙ্কর, পারফরম্যান্স ভিত্তিক।
আপনি যদি সত্যিই দ্রুত হ্যাশ লুক করতে চান তবে একটি ভয়ঙ্কর, ভয়ঙ্কর হ্যাক রয়েছে যা প্রকৃতপক্ষে খুব ভালভাবে কাজ করে। এটি হ'ল: আপনার কী / মানগুলি অস্থায়ী ফাইলে লিখুন, প্রতি লাইনে একটি করে, তারপরে 'গ্রেপ "^ $ কী"' ব্যবহার করুন, কাটা বা জাজক বা সেডযুক্ত পাইপগুলি ব্যবহার করে বা মানগুলি পুনরুদ্ধার করতে যা কিছু আছে।
যেমনটি আমি বলেছিলাম, এটি ভয়ানক শোনায়, এবং মনে হচ্ছে এটি ধীরে ধীরে হওয়া উচিত এবং সমস্ত ধরণের অপ্রয়োজনীয় আইও করা উচিত, তবে বাস্তবে এটি খুব দ্রুত (ডিস্ক ক্যাশে দুর্দান্ত, তাই না?) এমনকি খুব বড় হ্যাশের জন্যও টেবিল। আপনাকে কীগুলি স্বতন্ত্রতা নিজেকে প্রয়োগ করতে হবে, ইত্যাদি you যদি আপনার কেবল কয়েকশত এন্ট্রি থাকে তবে আউটপুট ফাইল / গ্রেপ কম্বো বেশ খানিকটা দ্রুত গতিতে চলেছে - আমার অভিজ্ঞতায় কয়েকগুণ দ্রুত। এটি স্মৃতিশক্তিও কম খায়।
এটি করার একটি উপায় এখানে:
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)
অবশ্যই, এটি ধীর, কিন্তু এটি ধীর নয়। আমি এটি আমার মেশিনে একটি এসএসডি এবং বিটিআরএফ দিয়ে পরীক্ষা করেছি এবং এটি প্রতি সেকেন্ডে প্রায় 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}
টেক্সট সরিয়ে ফেলা শুরু পরিবর্তনশীল সঞ্চিত মান শুরু থেকে Var ।
একটি সমাধান builtin ব্যাশ ব্যবহার করার কথা বিবেচনা পঠিত হিসাবে একটি 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 বাশের সাথে যাওয়ার উপায় 4. যদি আপনি বাশ 3 (ওএসএক্স, আপনি আপডেট করতে পারেন না এমন পুরানো ডিস্ট্রোস) এর সাথে আটকে থাকেন তবে আপনি এক্সপ্রেসও ব্যবহার করতে পারেন যা সর্বত্র হওয়া উচিত, একটি স্ট্রিং এবং নিয়মিত প্রকাশ। আমি বিশেষত এটি পছন্দ করি যখন অভিধান খুব বড় না হয়।
আপনার মানচিত্রটি স্ট্রিং হিসাবে লিখুন (বিভাজকটি ',' এবং শুরুতে এবং শেষেও নোট করুন)
animals=",moo:cow,woof:dog,"
মানগুলি নিষ্কাশন করতে একটি রেজেক্স ব্যবহার করুন
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 যুক্ত করা ()
দুটি জিনিস, আপনি / dev / shm (redhat) ব্যবহার করে যে কোনও কার্নেল ২.6-তে / tmp এর পরিবর্তে মেমরি ব্যবহার করতে পারেন অন্যান্য ডিস্ট্রোগুলি ভিন্ন হতে পারে। নীচে নীচে পড়া ব্যবহার করে হেইজেট পুনরায় প্রয়োগ করা যেতে পারে:
function hget {
while read key idx
do
if [ $key = $2 ]
then
echo $idx
return
fi
done < /dev/shm/hashmap.$1
}
সমস্ত কীগুলি অনন্য বলে ধরে নেওয়া ছাড়াও, রিটার্ন শর্ট সার্কিটগুলি রিড লুপ করে এবং সমস্ত এন্ট্রির মাধ্যমে পড়তে বাধা দেয়। যদি আপনার বাস্তবায়নে সদৃশ কী থাকতে পারে তবে কেবল ফিরে আসুন। এটি গ্রেপ এবং অ্যাজক উভয়ই পড়ার এবং কাঁটাচামড়ার ব্যয় সাশ্রয় করে। উভয় প্রয়োগের জন্য / dev / shm ব্যবহার করে সর্বশেষ প্রবেশের জন্য অনুসন্ধানের জন্য 3 টি প্রবেশের হ্যাশের সময় ব্যবহারের ফলে নীচের সময়টি দেওয়া হয়েছিল:
Grep / 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
পঠন / echo:
$ time echo $(hget FD oracle)
3
real 0m0.004s
user 0m0.000s
sys 0m0.004s
একাধিক অনুরোধে আমি কখনই কম দেখিনি 50% উন্নতি। ব্যবহারের কারণে এগুলি সমস্ত কাঁটা ওভার কাঁটাতে দায়ী করা যেতে পারে /dev/shm
।
একজন সহকর্মী এই থ্রেডটির স্রেফ উল্লেখ করেছেন। আমি বাশের মধ্যে হ্যাশ টেবিলগুলি স্বাধীনভাবে প্রয়োগ করেছি এবং এটি সংস্করণ ৪ এর উপর নির্ভর করে না, ২০১০ সালের মার্চ মাসে আমার একটি ব্লগ পোস্ট থেকে (এখানে উত্তরগুলির কিছু আগে ...) বাশ-এর হ্যাশ টেবিল শিরোনাম :
আমি পূর্বে ব্যবহার করা cksum
হ্যাশ করার কিন্তু যেহেতু অনুবাদ জাভার স্ট্রিং হ্যাশকোড নেটিভ ব্যাশ / 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[@])
আমি ব্যাশ 4 উপায়ও ব্যবহার করেছি তবে আমি বাগ খুঁজে পাই এবং বিরক্তিকর।
আমার ডায়নামিকভাবে এসোসিয়েটিভ অ্যারে সামগ্রী আপডেট করার দরকার ছিল তাই আমি এইভাবে ব্যবহার করেছি:
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 ডিকটিতে বিদ্যমান কীটিতে সংযোজন করার ফলে ইতিমধ্যে উপস্থিত থাকলে মান সংযোজন করতে পারে। সুতরাং উদাহরণস্বরূপ কিছু পুনরাবৃত্তি করার পরে মানটির বিষয়বস্তু ছিল "চেককোচেককঅল চেকক" এবং এটি ভাল ছিল না।
4.3.39 বাশ নিয়ে কোনও সমস্যা নেই যেখানে একটি বিদ্যমান কী সংযোজন করার অর্থ ইতিমধ্যে উপস্থিত থাকলে অ্যাকুয়ালের মানকে সাবস্টিচার করা।
আমি স্রেফ সাফ করার / স্থিতি ঘোষণার সমাধান করেছি সাইকেলের আগে চেক অ্যাসোসিয়েটিভ অ্যারে:
unset statusCheck; declare -A statusCheck
আমি গতিশীল ভেরিয়েবলগুলি ব্যবহার করে ব্যাশ 3 এ হ্যাশম্যাপগুলি তৈরি করি। আমি ব্যাখ্যা করেছি যে এটি আমার উত্তরটিতে কীভাবে কাজ করে: শেল স্ক্রিপ্টগুলিতে সহযোগী অ্যারেগুলি ys
এছাড়াও আপনি শেল_ম্যাপটিতে একবার দেখতে পারেন , যা ব্যাশ 3-এ তৈরি করা হ্যাশম্যাপ বাস্তবায়ন।