শেল স্ক্রিপ্টগুলিতে সহযোগী অ্যারে


116

আমাদের কাছে এমন একটি স্ক্রিপ্ট দরকার যা শেল স্ক্রিপ্টিং এর জন্য কোনও কাঠামোর জন্য অ্যাসোসিয়েটিভ অ্যারে বা মানচিত্রের মতো ডেটা স্ট্রাকচারের অনুকরণ করে?

উত্তর:


20

ইরফানের উত্তরে যুক্ত করতে , এখানে একটি সংক্ষিপ্ত এবং দ্রুত সংস্করণ হ'ল get()মানচিত্রের সামগ্রীতে এটির পুনরাবৃত্তি প্রয়োজন না:

get() {
    mapName=$1; key=$2

    map=${!mapName}
    value="$(echo $map |sed -e "s/.*--${key}=\([^ ]*\).*/\1/" -e 's/:SP:/ /g' )"
}

16
একটি সাবশেল এবং সেড কাঁটাচামচ করা খুব কমই অনুকূল। বাশ 4 এটিকে স্থানীয়ভাবে সমর্থন করে এবং ব্যাশ 3 এর আরও ভাল বিকল্প রয়েছে।
lhunath

149

আরেকটি বিকল্প, যদি পোর্টেবিলিটি আপনার প্রধান উদ্বেগ না হয় তবে শেলের মধ্যে নির্মিত অ্যা্যাসোসিয়েটিভ অ্যারেগুলি ব্যবহার করা। এটি ব্যাশ ৪.০ এ কাজ করা উচিত (এখন সর্বাধিক বড় ডিস্ট্রোজে উপলভ্য, যদিও আপনি নিজে এটি ইনস্টল না করে OS X এ নেই), ksh এবং zsh:

declare -A newmap
newmap[name]="Irfan Zulfiqar"
newmap[designation]=SSE
newmap[company]="My Own Company"

echo ${newmap[company]}
echo ${newmap[name]}

শেলের উপর নির্ভর করে আপনার typeset -A newmapপরিবর্তে একটি করার প্রয়োজন হতে পারে declare -A newmapবা কিছুতে এটি মোটেও প্রয়োজন হয় না।


উত্তর পোস্ট করার জন্য আপনাকে ধন্যবাদ, আমি মনে করি যে ছেলেদের জন্য যারা 4.0 বা তার বেশি বাশ ব্যবহার করবেন তাদের পক্ষে এটি করার সবচেয়ে ভাল উপায়।
ইরফান জুলফিকার 6

BASH_VERSION সেট করা আছে তা নিশ্চিত করার জন্য আমি কিছুটা ক্লডজ যুক্ত করব এবং> = 4 4. এবং হ্যাঁ, BASH 4 সত্যিই, সত্যিই দুর্দান্ত!
টিম পোস্ট

আমি এই জাতীয় কিছু ব্যবহার করছি। অ্যারে সূচক / সাবস্ক্রিপ্ট উপস্থিত না থাকায় ত্রুটিটি "ধরা" দেওয়ার সর্বোত্তম উপায় কী? উদাহরণস্বরূপ, আমি যদি কমান্ড লাইন বিকল্প হিসাবে সাবস্ক্রিপ্টটি গ্রহণ করি, এবং ব্যবহারকারী একটি টাইপ তৈরি করে "ডিজাইনেটিও" প্রবেশ করেন? আমি একটি "খারাপ অ্যারে সাবস্ক্রিপ্ট" ত্রুটি পেয়েছি তবে অ্যারে দেখার সময় কীভাবে ইনপুটটিকে বৈধতা দেওয়া যায় না, যদি সম্ভব হয়?
জের

3
@ জের এটি অত্যন্ত অস্পষ্ট, তবে শেলের মধ্যে কোনও ভেরিয়েবল সেট করা আছে কিনা তা নির্ধারণ করতে আপনি ব্যবহার করতে পারেন test -z ${variable+x}(এটি xকোনও বিষয় নয়, এটি কোনও স্ট্রিং হতে পারে)। বাশে কোনও সাহসী অ্যারের জন্য, আপনি একই রকম করতে পারেন; ব্যবহার test -z ${map[key]+x}
ব্রায়ান ক্যাম্পবেল

95

আর একটি নন-ব্যাশ 4 টি উপায়।

#!/bin/bash

# A pretend Python dictionary with bash 3 
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

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

আপনি সেখানে অনুসন্ধানের জন্য যদি একটি বিবৃতি নিক্ষেপ করতে পারেন। যদি [[$ var = ~ / ব্লাহ /]]। বা যাই হোক না কেন.


2
এই পদ্ধতিটি ভাল যখন আপনার কাছে বাশ 4 নেই good তবে আমি মনে করি যে ভ্যালুটি আনবে সেই লাইনটি এইভাবে নিরাপদ হবে: VALUE = $ {প্রাণী # *:}} একটি মাত্র # টি অক্ষরের সাথে মিলটি প্রথম ":" এ থামবে। এটি মানগুলিকে ":" ধারণ করতেও সহায়তা করে।
সিড-লে-পিংগুইন

@ সিড-লে-পিংগুইন ~ এটি দুর্দান্ত পয়েন্ট! আমি তা ধরিনি। আমি আপনার প্রস্তাবিত উন্নতি প্রতিফলিত করতে আমার পোস্ট সম্পাদনা করেছি।
বুবনফ

1
এটি বেস প্যারামিটার সাবস্টিটিউশন ব্যবহার করে সহযোগী অ্যারেগুলির একটি সুন্দর হ্যাকিশ অনুকরণ। "কী" প্যারাম-সাব কোলনের আগে সবকিছুকে প্রতিস্থাপন করে এবং মান প্যাটার্ন কোলনের পরে সমস্ত কিছু প্রতিস্থাপন করে। একটি রেজেক্স ওয়াইল্ডকার্ড ম্যাচের মতো। তাই নয় একটি সত্য এসসিয়েতিভ আরে। BASH 3 বা নীচে আপনার হ্যাশ / এসোসিয়েটিভ অ্যারে-এর মতো কার্যকারিতা বোঝার সহজ উপায় না লাগলে প্রস্তাবিত নয়। যদিও এটি কাজ করে! আরো এখানে: tldp.org/LDP/abs/html/parameter-substitution.html#PSOREX2
Bubnoff

1
এটি কোনও সহযোগী অ্যারে বাস্তবায়িত করে না কারণ এটি কী দ্বারা কোনও আইটেম সন্ধান করার কোনও উপায় সরবরাহ করে না। এটি কেবল একটি সংখ্যাসূচক সূচি থেকে প্রতিটি কী (এবং মান) সন্ধানের জন্য একটি উপায় সরবরাহ করে। (অ্যারের মাধ্যমে পুনরাবৃত্তি করে কোনও আইটেম কী দ্বারা সন্ধান করা যেতে পারে তবে এটি কোনও সহযোগী অ্যারের জন্য পছন্দসই নয়))
এরিক পোস্টপিসিল

পুনঃটুইট এটি কেবল একটি হ্যাক। এটি কোনও ব্যক্তিকে সেটআপে পরিচিত সিনট্যাক্স ব্যবহার করতে দেয় তবে আপনার অ্যারের মাধ্যমে পুনরায় পুনরুক্তি প্রয়োজন। আমি আমার আগের মন্তব্যে পরিষ্কার হওয়ার চেষ্টা করেছি যে এটি অবশ্যই কোনও সাহসী অ্যারে নয় এবং আপনার বিকল্প থাকলে আমি এটিও সুপারিশ করি না। আমার পক্ষে এটির পক্ষে একমাত্র বক্তব্য, পাইথনের মতো অন্যান্য ভাষার সাথে পরিচিতদের পক্ষে এটি লেখা এবং ব্যবহার করা সহজ। আপনি যদি এমন একটি জায়গায় পৌঁছে যান যেখানে আপনি বাস্তবে 3 বেসে সহযোগী অ্যারেগুলি বাস্তবায়ন করতে চান তবে আপনাকে আপনার পদক্ষেপগুলি কিছুটা পিছিয়ে নিতে হবে।
বুবনেফ

34

আমি মনে করি যে আপনাকে পিছনে পদক্ষেপ নিতে হবে এবং একটি মানচিত্র বা সহযোগী অ্যারে আসলে কী তা নিয়ে ভাবতে হবে। এগুলি হ'ল একটি প্রদত্ত কীটির জন্য একটি মান সংরক্ষণ করার উপায় এবং সেই মানটি দ্রুত এবং দক্ষতার সাথে ফিরে পাওয়া। আপনি প্রতিটি মূল মান জুটি পুনরুদ্ধার করতে কীগুলি বা পুনরুদ্ধার করতে বা কী এবং তার সাথে সম্পর্কিত মানগুলি মুছতে সক্ষম হতে পারেন।

এখন, শেল স্ক্রিপ্টিংয়ে আপনি সমস্ত সময় ব্যবহার করেন এমন ডেটা স্ট্রাকচারের কথা চিন্তা করুন এবং এমনকি শেলটিতে কোনও স্ক্রিপ্ট না লিখেও, যার মধ্যে এই বৈশিষ্ট্য রয়েছে। তুলবেন? এটি ফাইল সিস্টেম।

সত্যই, শেল প্রোগ্রামিংয়ে আপনাকে একটি এসোসিয়েটিভ অ্যারে থাকা দরকার কেবল একটি অস্থায়ী ডিরেক্টরি। mktemp -dআপনার সহযোগী অ্যারে নির্মাণকারী:

prefix=$(basename -- "$0")
map=$(mktemp -dt ${prefix})
echo >${map}/key somevalue
value=$(cat ${map}/key)

আপনি যদি ব্যবহার করে মনে করেন না echoএবং cat, আপনি সর্বদা কিছুটা ছোট র‌্যাপার লিখতে পারেন; এগুলি ইরফানের মডেল করা হয়, যদিও তারা স্বেচ্ছাচারী ভেরিয়েবলগুলি সেট করার পরিবর্তে কেবলমাত্র আউটপুট দেয় $value:

#!/bin/sh

prefix=$(basename -- "$0")
mapdir=$(mktemp -dt ${prefix})
trap 'rm -r ${mapdir}' EXIT

put() {
  [ "$#" != 3 ] && exit 1
  mapname=$1; key=$2; value=$3
  [ -d "${mapdir}/${mapname}" ] || mkdir "${mapdir}/${mapname}"
  echo $value >"${mapdir}/${mapname}/${key}"
}

get() {
  [ "$#" != 2 ] && exit 1
  mapname=$1; key=$2
  cat "${mapdir}/${mapname}/${key}"
}

put "newMap" "name" "Irfan Zulfiqar"
put "newMap" "designation" "SSE"
put "newMap" "company" "My Own Company"

value=$(get "newMap" "company")
echo $value

value=$(get "newMap" "name")
echo $value

সম্পাদনা করুন : এই পদ্ধতিটি প্রশ্নকর্তার পরামর্শ অনুসারে লিনিয়ার অনুসন্ধানের তুলনায় বেশ কিছুটা দ্রুত, তেমনি আরও শক্তিশালী (এটি কী এবং মানগুলিকে -, =, স্থান, qnd ": এসপি:" অন্তর্ভুক্ত করার অনুমতি দেয়)। এটি ফাইল সিস্টেমটি ব্যবহার করে তা ধীর করে দেয় না; আপনি কল না করাতে এই ফাইলগুলি কখনই ডিস্কে লিখিত হওয়ার নিশ্চয়তা দেয় না sync; অল্প সময়ের জন্য এই জাতীয় অস্থায়ী ফাইলগুলির জন্য, তাদের অনেকগুলিই কখনই ডিস্কে লিখিত না হওয়ার সম্ভাবনা কম।

আমি নীচের ড্রাইভার প্রোগ্রামটি ব্যবহার করে ইরফানের কোড, জেরির ইরফানের কোডটিতে পরিবর্তন এবং আমার কোডের কয়েকটি মানদণ্ড করেছি:

#!/bin/sh

mapimpl=$1
numkeys=$2
numvals=$3

. ./${mapimpl}.sh    #/ <- fix broken stack overflow syntax highlighting

for (( i = 0 ; $i < $numkeys ; i += 1 ))
do
    for (( j = 0 ; $j < $numvals ; j += 1 ))
    do
        put "newMap" "key$i" "value$j"
        get "newMap" "key$i"
    done
done

ফলাফলগুলো:

    $ সময় ./driver.sh ইরফান 10 5

    বাস্তব 0m0.975s
    ব্যবহারকারী 0m0.280s
    sys 0m0.691s

    $ সময় ./driver.sh ব্রায়ান 10 5

    আসল 0m0.226s
    ব্যবহারকারী 0m0.057s
    sys 0m0.123s

    $ সময় ./driver.sh জেরি 10 5

    আসল 0m0.706s
    ব্যবহারকারী 0m0.228s
    ss 0m0.530s

    $ সময় ./driver.sh ইরফান 100 5

    বাস্তব 0m10.633s
    ব্যবহারকারী 0m4.366s
    ss 0m7.127s

    $ সময় ./driver.sh ব্রায়ান 100 5

    বাস্তব 0m1.682s
    ব্যবহারকারী 0m0.546s
    sys 0m1.082s

    $ সময় ./driver.sh জেরি 100 5

    বাস্তব 0 মি 9.315 সে
    ব্যবহারকারী 0m4.565s
    ss 0m5.446s

    $ সময় ./driver.sh ইরফান 10 500

    বাস্তব 1 মি 46.197 সে
    ব্যবহারকারী 0m44.869s
    sys 1m12.282s

    $ সময় ./driver.sh ব্রায়ান 10 500

    আসল 0 মি 16.003 এস
    ব্যবহারকারী 0m5.135s
    ss 0m10.396s

    $ সময়। / driver.sh জেরি 10 500

    বাস্তব 1m24.414s
    ব্যবহারকারী 0m39.696s
    sys 0m54.834s

    $ সময় ./driver.sh ইরফান 1000 5

    বাস্তব 4m25.145s
    ব্যবহারকারী 3m17.286s
    sys 1m21.490s

    $ সময় ./driver.sh ব্রায়ান 1000 5

    বাস্তব 0m19.442s
    ব্যবহারকারী 0m5.287s
    sys 0m10.751s

    $ সময় ./driver.sh জেরি 1000 5

    বাস্তব 5m29.136s
    ব্যবহারকারী 4m48.926s
    sys 0m59.336s


1
আমি মনে করি না আপনি মানচিত্রের জন্য ফাইল সিস্টেম ব্যবহার করা উচিত, যা মূলত মেমোরির ক্ষেত্রে আপনি মোটামুটি দ্রুত করতে পারেন এমন কোনও কিছুর জন্য আইও ব্যবহার করে।
ইরফান জুলফিকার 6

9
অগত্যা ফাইলগুলি ডিস্কে লেখা হবে না; আপনি সিঙ্ককে কল না করলে অপারেটিং সিস্টেম এগুলি কেবল মেমরিতে রেখে দেয় leave আপনার কোডটি সিডে কল করছে এবং বেশ কয়েকটি লিনিয়ার অনুসন্ধান করছে, যা সবগুলি খুব ধীর। আমি কিছু দ্রুত বেনমার্ক করেছি এবং আমার সংস্করণটি 5-35 গুণ বেশি দ্রুত।
ব্রায়ান ক্যাম্পবেল

অন্যদিকে, bash4 এর নেটিভ অ্যারেগুলি একটি পদ্ধতির তুলনায় উল্লেখযোগ্যভাবে আরও ভাল এবং bash3 এ আপনি এখনও ডিক্লেয়ার এবং ইন্ডিয়ারেশন ব্যবহার করে কাঁটাচামচ না করে সমস্ত কিছু ডিস্কের বাইরে রাখতে পারেন।
lhunath

7
"দ্রুত" এবং "শেল" সত্যিই যাই হোক না কেন একসাথে যাবেন না: অবশ্যই আমরা "মিনিস্টিওল আইও এড়ানো" স্তরে যে ধরণের গতির সমস্যার কথা বলছি তার জন্য নয়। কোনও আইওর গ্যারান্টি রাখতে আপনি অনুসন্ধান করতে এবং / dev / shm ব্যবহার করতে পারেন।
jmtd

2
এই সমাধানটি আমাকে বিস্মিত করেছে, এবং কেবল দুর্দান্ত। এখনও 2016 সালে সত্য holds এটি সত্যই গ্রহণযোগ্য উত্তর হওয়া উচিত।
গর্ডন

7

বাশ 4 এটিকে স্থানীয়ভাবে সমর্থন করে। ব্যবহার করবেন না grepবা eval, এগুলি হ্যাকগুলির কুৎসিত।

একটি ভার্বোজের জন্য উদাহরণ কোড সহ বিশদ উত্তর দেখুন: /programming/3467959


7
####################################################################
# Bash v3 does not support associative arrays
# and we cannot use ksh since all generic scripts are on bash
# Usage: map_put map_name key value
#
function map_put
{
    alias "${1}$2"="$3"
}

# map_get map_name key
# @return value
#
function map_get
{
    alias "${1}$2" | awk -F"'" '{ print $2; }'
}

# map_keys map_name 
# @return map keys
#
function map_keys
{
    alias -p | grep $1 | cut -d'=' -f1 | awk -F"$1" '{print $2; }'
}

উদাহরণ:

mapName=$(basename $0)_map_
map_put $mapName "name" "Irfan Zulfiqar"
map_put $mapName "designation" "SSE"

for key in $(map_keys $mapName)
do
    echo "$key = $(map_get $mapName $key)
done

4

এখন এই প্রশ্নের উত্তর।

নিম্নলিখিত স্ক্রিপ্টগুলি শেল স্ক্রিপ্টগুলিতে সহযোগী অ্যারেগুলি অনুকরণ করে। এটি সহজ এবং বুঝতে খুব সহজ।

মানচিত্রটি কখনই শেষ না হওয়া স্ট্রিং ছাড়া কী-ভ্যালুপায়ার - নাম = ইরফান - ডিজাইনেশন = এসএসই - কম্পিউটারে = আমার: এসপি: নিজস্ব: এসপি: সংস্থা হিসাবে সংরক্ষণ করা হয়েছে

মানগুলির জন্য স্পেসগুলি ': SP:' দিয়ে প্রতিস্থাপন করা হয়

put() {
    if [ "$#" != 3 ]; then exit 1; fi
    mapName=$1; key=$2; value=`echo $3 | sed -e "s/ /:SP:/g"`
    eval map="\"\$$mapName\""
    map="`echo "$map" | sed -e "s/--$key=[^ ]*//g"` --$key=$value"
    eval $mapName="\"$map\""
}

get() {
    mapName=$1; key=$2; valueFound="false"

    eval map=\$$mapName

    for keyValuePair in ${map};
    do
        case "$keyValuePair" in
            --$key=*) value=`echo "$keyValuePair" | sed -e 's/^[^=]*=//'`
                      valueFound="true"
        esac
        if [ "$valueFound" == "true" ]; then break; fi
    done
    value=`echo $value | sed -e "s/:SP:/ /g"`
}

put "newMap" "name" "Irfan Zulfiqar"
put "newMap" "designation" "SSE"
put "newMap" "company" "My Own Company"

get "newMap" "company"
echo $value

get "newMap" "name"
echo $value

সম্পাদনা: সমস্ত কীগুলি আনার জন্য সবেমাত্র অন্য পদ্ধতি যুক্ত করা হয়েছে।

getKeySet() {
    if [ "$#" != 1 ]; 
    then 
        exit 1; 
    fi

    mapName=$1; 

    eval map="\"\$$mapName\""

    keySet=`
           echo $map | 
           sed -e "s/=[^ ]*//g" -e "s/\([ ]*\)--/\1/g"
          `
}

1
আপনি এটি evalতথ্য কোডটিকে যেমন বাশ কোড হিসাবে চিহ্নিত করছেন এবং আরও কী: আপনি এটি সঠিকভাবে উদ্ধৃতি দিতে ব্যর্থ হন। উভয়ই বিপুল পরিমাণে বাগ এবং স্বতঃস্ফূর্ত কোড ইনজেকশন সৃষ্টি করে।
lhunath

3

বাশ 3 এর জন্য একটি বিশেষ কেস রয়েছে যার একটি দুর্দান্ত এবং সহজ সমাধান রয়েছে:

আপনি যদি অনেকগুলি ভেরিয়েবল পরিচালনা করতে চান না বা কীগুলি কেবল অবৈধ ভেরিয়েবল শনাক্তকারী এবং আপনার অ্যারেতে 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[$?]}

মনে রাখবেন, একক উদ্ধৃতি ব্যবহার করুন case, অন্যথায় এটি গ্লোব্বিংয়ের সাথে সম্পর্কিত। স্ট্যাটিক / হিমায়িত হ্যাশগুলির জন্য শুরু থেকেই সত্যই কার্যকর, তবে একটি hash_keys=()অ্যারে থেকে সূচক জেনারেটর লিখতে পারে ।

দেখুন, এটি প্রথমটির ডিফল্ট, সুতরাং আপনি জিরোথ উপাদানটি আলাদা করতে চাইতে পারেন:

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

hash_vals=("",           # sort of like returning null/nil for a non existent key
           "foo_val"
           "bar_val"
           "baz_val");

hash_index "foo" || echo ${hash_vals[$?]}  # It can't get more readable than this

কেভেট: দৈর্ঘ্য এখন ভুল।

বিকল্পভাবে, আপনি যদি শূন্য-ভিত্তিক সূচী রাখতে চান, আপনি অন্য সূচক মান সংরক্ষণ করতে পারবেন এবং অস্তিত্বযুক্ত কী থেকে রক্ষা করতে পারেন, তবে এটি কম পাঠযোগ্য:

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

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

hash_index "foo"
[[ $? -ne 255 ]] && echo ${hash_vals[$?]}

বা, দৈর্ঘ্য সঠিক রাখতে, অফসেটকে একের পর এক অফসেট করুন:

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

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

hash_index "foo" || echo ${hash_vals[$(($? - 1))]}

2

আপনি গতিশীল পরিবর্তনশীল নামগুলি ব্যবহার করতে পারেন এবং ভেরিয়েবলের নামগুলি হ্যাশম্যাপের কীগুলির মতো কাজ করতে দিন।

উদাহরণস্বরূপ, উদাহরণস্বরূপ নমুনা হিসাবে আপনার কাছে যদি দুটি কলাম, নাম, ক্রেডিট সহ একটি ইনপুট ফাইল থাকে এবং আপনি প্রতিটি ব্যবহারকারীর আয়কে যোগ করতে চান:

Mary 100
John 200
Mary 50
John 300
Paul 100
Paul 400
David 100

কমান্ড বেলো ম্যাপ _ $ {ব্যক্তি} আকারে গতিশীল ভেরিয়েবলগুলি কী হিসাবে ব্যবহার করে সমস্ত কিছু সংযুক্ত করবে :

while read -r person money; ((map_$person+=$money)); done < <(cat INCOME_REPORT.log)

ফলাফলগুলি পড়তে:

set | grep map

আউটপুটটি হবে:

map_David=100
map_John=500
map_Mary=150
map_Paul=500

এই কৌশলগুলির বিশদ বিবরণে , আমি গিটহাবের উপর একটি ফাংশন বিকাশ করছি যা হ্যাশম্যাপ অবজেক্ট , শেল_ম্যাপের মতো কাজ করে ।

" হ্যাশম্যাপ দৃষ্টান্তগুলি " তৈরি করতে শেল_ম্যাপ ফাংশনটি বিভিন্ন নামে নিজের অনুলিপি তৈরি করতে সক্ষম। প্রতিটি নতুন ফাংশনের অনুলিপিতে আলাদা $ FUNCNAME ভেরিয়েবল থাকবে। $ FUNCNAME এর পরে প্রতিটি মানচিত্রের উদাহরণের জন্য একটি নেমস্পেস তৈরি করতে ব্যবহৃত হয়।

মানচিত্র কীগুলি বিশ্বব্যাপী পরিবর্তনশীল $ FUNCNAME_DATA_ global KEY আকারে, যেখানে $ KEY মানচিত্রে যুক্ত হওয়া কী। এই ভেরিয়েবলগুলি ডায়নামিক ভেরিয়েবল

বেলো আমি এর একটি সরলীকৃত সংস্করণ রাখব যাতে আপনি উদাহরণ হিসাবে ব্যবহার করতে পারেন।

#!/bin/bash

shell_map () {
    local METHOD="$1"

    case $METHOD in
    new)
        local NEW_MAP="$2"

        # loads shell_map function declaration
        test -n "$(declare -f shell_map)" || return

        # declares in the Global Scope a copy of shell_map, under a new name.
        eval "${_/shell_map/$2}"
    ;;
    put)
        local KEY="$2"  
        local VALUE="$3"

        # declares a variable in the global scope
        eval ${FUNCNAME}_DATA_${KEY}='$VALUE'
    ;;
    get)
        local KEY="$2"
        local VALUE="${FUNCNAME}_DATA_${KEY}"
        echo "${!VALUE}"
    ;;
    keys)
        declare | grep -Po "(?<=${FUNCNAME}_DATA_)\w+((?=\=))"
    ;;
    name)
        echo $FUNCNAME
    ;;
    contains_key)
        local KEY="$2"
        compgen -v ${FUNCNAME}_DATA_${KEY} > /dev/null && return 0 || return 1
    ;;
    clear_all)
        while read var; do  
            unset $var
        done < <(compgen -v ${FUNCNAME}_DATA_)
    ;;
    remove)
        local KEY="$2"
        unset ${FUNCNAME}_DATA_${KEY}
    ;;
    size)
        compgen -v ${FUNCNAME}_DATA_${KEY} | wc -l
    ;;
    *)
        echo "unsupported operation '$1'."
        return 1
    ;;
    esac
}

ব্যবহার:

shell_map new credit
credit put Mary 100
credit put John 200
for customer in `credit keys`; do 
    value=`credit get $customer`       
    echo "customer $customer has $value"
done
credit contains_key "Mary" && echo "Mary has credit!"

2

তবুও অন্য একটি নন-ব্যাশ -4 (অর্থাত্, ব্যাশ 3, ম্যাক-সামঞ্জস্যপূর্ণ) উপায়:

val_of_key() {
    case $1 in
        'A1') echo 'aaa';;
        'B2') echo 'bbb';;
        'C3') echo 'ccc';;
        *) echo 'zzz';;
    esac
}

for x in 'A1' 'B2' 'C3' 'D4'; do
    y=$(val_of_key "$x")
    echo "$x => $y"
done

ছাপে:

A1 => aaa
B2 => bbb
C3 => ccc
D4 => zzz

caseএকটি মিশুক অ্যারের মতো কাজ করে ফাংশন । দুর্ভাগ্যক্রমে এটি ব্যবহার করতে পারে না return, সুতরাং echoএটির আউটপুটটিও রয়েছে তবে এটি কোনও সমস্যা নয়, যদি না আপনি শুদ্ধবাদী হয়ে থাকেন যা সাব-শেলগুলি বন্ধ করা থেকে বিরত থাকে।


1

আমি দুঃখের সাথে প্রশ্নটি আগে দেখতে পেলাম না - আমি গ্রন্থাগার শেল-কাঠামো লিখেছি যা অন্যদের মধ্যে মানচিত্র (সহযোগী অ্যারে) রয়েছে। এর শেষ সংস্করণটি এখানে পাওয়া যাবে

উদাহরণ:

#!/bin/bash 
#include map library
shF_PATH_TO_LIB="/usr/lib/shell-framework"
source "${shF_PATH_TO_LIB}/map"

#simple example get/put
putMapValue "mapName" "mapKey1" "map Value 2"
echo "mapName[mapKey1]: $(getMapValue "mapName" "mapKey1")"

#redefine old value to new
putMapValue "mapName" "mapKey1" "map Value 1"
echo "after change mapName[mapKey1]: $(getMapValue "mapName" "mapKey1")"

#add two new pairs key/values and print all keys
putMapValue "mapName" "mapKey2" "map Value 2"
putMapValue "mapName" "mapKey3" "map Value 3"
echo -e "mapName keys are \n$(getMapKeys "mapName")"

#create new map
putMapValue "subMapName" "subMapKey1" "sub map Value 1"
putMapValue "subMapName" "subMapKey2" "sub map Value 2"

#and put it in mapName under key "mapKey4"
putMapValue "mapName" "mapKey4" "subMapName"

#check if under two key were placed maps
echo "is map mapName[mapKey3]? - $(if isMap "$(getMapValue "mapName" "mapKey3")" ; then echo Yes; else echo No; fi)"
echo "is map mapName[mapKey4]? - $(if isMap "$(getMapValue "mapName" "mapKey4")" ; then echo Yes; else echo No; fi)"

#print map with sub maps
printf "%s\n" "$(mapToString "mapName")"

1

অন্য বিকল্প যুক্ত করা, যদি জকিউ উপলব্ধ থাকে:

export NAMES="{
  \"Mary\":\"100\",
  \"John\":\"200\",
  \"Mary\":\"50\",
  \"John\":\"300\",
  \"Paul\":\"100\",
  \"Paul\":\"400\",
  \"David\":\"100\"
}"
export NAME=David
echo $NAMES | jq --arg v "$NAME" '.[$v]' | tr -d '"' 

0

আমি এটি সত্য বলে খুঁজে পেয়েছি, যেমন ইতিমধ্যে উল্লিখিত হয়েছে যে সর্বোত্তম পারফর্মিং পদ্ধতিটি কোনও ফাইলের কী / ভ্যালস লিখতে হয় এবং সেগুলি পুনরুদ্ধারের জন্য গ্রেপ / অ্যাডক ব্যবহার করা হয়। এটি সমস্ত ধরণের অপ্রয়োজনীয় আইওর মতো শোনাচ্ছে তবে ডিস্ক ক্যাশে এটি খুব কার্যকর করে তোলে - উপরের যে কোনও একটি পদ্ধতি (মাপদণ্ডের শো হিসাবে) ব্যবহার করে মেমরিতে এগুলি সংরক্ষণ করার চেষ্টা করার চেয়ে অনেক দ্রুত।

আমি এখানে পছন্দ করি একটি দ্রুত এবং পরিষ্কার পদ্ধতি:

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

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

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

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

echo `hget capitols France` and `hget capitols Netherlands` and `hget capitols Spain`

আপনি যদি প্রতি কী প্রতি একক মান প্রয়োগ করতে চান তবে আপনি hp () এ কিছুটা গ্রেপ / সেড ক্রিয়াও করতে পারেন।


0

বেশ কয়েক বছর আগে আমি বাশের জন্য স্ক্রিপ্ট লাইব্রেরি লিখেছিলাম যা অন্যান্য বৈশিষ্ট্যগুলির মধ্যে (লগিং, কনফিগারেশন ফাইলগুলি, কমান্ড লাইন আর্গুমেন্টের জন্য বর্ধিত সহায়তা, সহায়তা জেনারেট, ইউনিট টেস্টিং ইত্যাদি) সমর্থন করে। লাইব্রেরিতে এসোসিয়েটিভ অ্যারেগুলির জন্য একটি মোড়ক রয়েছে এবং স্বয়ংক্রিয়ভাবে উপযুক্ত মডেলের দিকে চলে যায় (bash4 এর জন্য অভ্যন্তরীণ এবং পূর্ববর্তী সংস্করণগুলির জন্য অনুকরণীয়)। এটিকে শেল-ফ্রেমওয়ার্ক বলা হত এবং এটি আরিগো.থজ.চইচে হোস্ট করা হয়েছিল তবে আজ সংস্থানটি বন্ধ রয়েছে। যদি কারও এখনও এটির প্রয়োজন হয় তবে আমি এটি আপনার সাথে ভাগ করে নিতে পারি।


এটি গিথুবকে আঁকিয়ে রাখার মতো হতে পারে
মার্ক কে কোয়ান

0

শেলের ডেটা স্ট্রাকচারের মতো কোনও অন্তর্নির্মিত মানচিত্র নেই, আমি এর মতো আইটেমগুলি বর্ণনা করতে কাঁচা স্ট্রিং ব্যবহার করি:

ARRAY=(
    "item_A|attr1|attr2|attr3"
    "item_B|attr1|attr2|attr3"
    "..."
)

আইটেম এবং এর বৈশিষ্ট্যগুলি নিষ্কাশন করার সময়:

for item in "${ARRAY[@]}"
do
    item_name=$(echo "${item}"|awk -F "|" '{print $1}')
    item_attr1=$(echo "${item}"|awk -F "|" '{print $2}')
    item_attr2=$(echo "${item}"|awk -F "|" '{print $3}')

    echo "${item_name}"
    echo "${item_attr1}"
    echo "${item_attr2}"
done

এটি অন্য লোকের জবাবের চেয়ে চতুর নয় বলে মনে হয়, তবে নতুন লোকদের শেল দেওয়া সহজ।


-1

আমি নীচের সাথে ভাদিমের সমাধানটি সংশোধন করেছি:

####################################################################
# Bash v3 does not support associative arrays
# and we cannot use ksh since all generic scripts are on bash
# Usage: map_put map_name key value
#
function map_put
{
    alias "${1}$2"="$3"
}

# map_get map_name key
# @return value
#
function map_get {
    if type -p "${1}$2"
        then
            alias "${1}$2" | awk -F "'" '{ print $2; }';
    fi
}

# map_keys map_name 
# @return map keys
#
function map_keys
{
    alias -p | grep $1 | cut -d'=' -f1 | awk -F"$1" '{print $2; }'
}

পরিবর্তনটি ম্যাপ_জেটে ত্রুটি ফিরে আসা থেকে রোধ করার জন্য আপনি যদি উপস্থিত নেই এমন কোনও কীটির অনুরোধ করেন তবে এর পার্শ্ব-প্রতিক্রিয়াটি হ'ল এটি নিঃশব্দে নিখোঁজ থাকা মানচিত্রগুলিও উপেক্ষা করবে, তবে এটি আমার ব্যবহারের ক্ষেত্রে আরও উপযুক্ত since কোনও লুপে আইটেমগুলি এড়ানোর জন্য কোনও কীটি পরীক্ষা করতে চেয়েছিলেন।


-1

দেরিতে জবাব, তবে এই জাতীয় সমস্যাটিকে সমাধান করে বিবেচনা করুন, ব্যাশ অন্তর্নির্মিত একটি ইউএফডাব্লু ফায়ারওয়াল স্ক্রিপ্ট থেকে কোড স্নিপেটের মধ্যে বর্ণিত হিসাবে পড়ুন using এই পদ্ধতির পছন্দসই হিসাবে অনেক সীমিত ক্ষেত্রের সেটগুলি (কেবল 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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.