Asociatyvinės matricos korpuso scenarijuose

Mums reikėjo scenarijaus, kuris imituoja asociatyvias masyvus arba žemėlapį kaip Shell Scripting duomenų struktūrą, bet kokį kūną?

98
27 марта '09 в 10:37 2009-03-27 10:37 nustatė Irfan Zulfiqar, kovo 27 d., „09, 10:37 2009-03-27 10:37
@ 18 atsakymų

Jei norite pridėti „ Irfan“ atsakymą , tai yra trumpesnė ir greitesnė get() versija, nes žemėlapio turiniui nereikia kartoti:

 get() { mapName=$1; key=$2 map=${!mapName} value="$(echo $map |sed -e "s/.*--${key}=\([^ ]*\).*/\1/" -e 's/:SP:/ /g' )" } 
20
27 марта '09 в 19:48 2009-03-27 19:48 atsakymą pateikė Jerry Penner, kovo 27 d., 09:48, 2009-03-27 19:48

Kita galimybė, jei perkeliamumas nėra jūsų pagrindinis rūpestis, yra naudoti į korpusą įmontuotas asociacijas. Tai turėtų veikti „bash 4.0“ (prieinama dabar daugelyje pagrindinių paskirstymų, bet ne „OS X“, nebent jūs ją įdiegtumėte), ksh ir zsh:

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

Priklausomai nuo pakuotės, jums gali prireikti typeset -A newmap vietoj declare -A newmap , arba kai kuriais atvejais tai nebūtinai reikalinga.

120
27 марта '09 в 22:22 2009-03-27 22:22 atsakymą pateikė Brian Campbell, kovo 27 d., 09:22, 2009-03-27 22:22

Kitas būdas nėra bash 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" 

Taip pat galite nurodyti, jei norite ieškoti. jei [[$ var = ~ / blah /]]. arba kažkas kita.

83
15 дек. Atsakymą pateikė Bubnoff gruodžio 15 d. 2010-12-15 01:14 '10 ne 1:14 2010-12-15 01:14

Manau, kad reikia atsigręžti ir pagalvoti apie tai, kas yra žemėlapis ar asociatyvus masyvas. Visa tai yra būdas išsaugoti tam tikro rakto vertę ir greitai bei efektyviai gauti šią vertę. Taip pat galite kartoti per klavišus, kad gautumėte kiekvieną pagrindinės vertės porą, arba ištrinkite raktus ir su jais susijusias reikšmes.

Dabar pagalvokite apie duomenų struktūrą, kurią visą laiką naudojate šifravimo skriptuose, ir netgi į apvalkalą be scenarijaus įrašo, turinčio šias savybes. Dead end? Tai failų sistema.

Iš tiesų, viskas, ko jums reikia, norint turėti asociatyviąją masyvą apvalkalo programavime, yra laikinas katalogas. mktemp -d yra jūsų asociatyvus masyvo konstruktorius:

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

Jei nenorite naudoti echo ir cat , visada galite parašyti keletą mažų pakuočių; Šie modeliai yra modeliuojami pagal „Irfan“, nors jie paprasčiausiai išleidžia vertę, o ne nustato savavališkus „ $value tipo kintamuosius:

 #!/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 

redaguoti . Šis požiūris iš tikrųjų yra gana greitas nei tiesinė paieška, kurią siūlo mokslininkas, ir taip pat patikimesnis (leidžia raktams ir reikšmėms turėti -, =, tarpą, qnd ": SP:"). Tai, kad ji naudoja failų sistemą, nesilpnina; šie failai niekada tikrai neįrašomi į diską, nebent skambinate sync ; tokiems laikiniems failams, kuriuose yra trumpas tarnavimo laikas, mažai tikėtina, kad daugelis jų kada nors bus įrašyti į diską.

Aš atlikdavau keletą „Irfan“ kodo testų: „Irfan“ kodo Jerry modifikaciją ir mano kodą naudodamas šią tvarkyklės programą:

 #!/bin/sh mapimpl=$1 numkeys=$2 numvals=$3 . ./${mapimpl}.sh #/ <- fix broken ngn-wiki.ru 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 

Rezultatai:

 $ time ./driver.sh irfan 10 5 tikras 0m0.975s naudotojas 0m0.280s sys 0m0.691s $ time ./driver.sh brian 10 5 tikras 0m0,226s naudotojas 0m0.057s sys 0m0.123s $ time ./driver.sh jerry 10 5 tikras 0m0.706s naudotojas 0m0.228s sys 0m0.530s $ time ./driver.sh irfan 100 5 reali 0m10.633s naudotojas 0m4.366s sys 0m7.127s $ time ./driver.sh brian 100 5 tikras 0m1.682s naudotojas 0m0.546s sys 0m1.082s $ time ./driver.sh jerry 100 5 tikras 0m9.315s naudotojas 0m4.565s sys 0m5.446s $ time ./driver.sh irfan 10 500 tikras 1m46.197s naudotojas 0m44.869s sys 1m12.282s $ time ./driver.sh brian 10 500 reali 0m16.003s naudotojas 0m5.135s sys 0m10.396s $ time ./driver.sh jerry 10 500 tikras 1m24.414s naudotojas 0m39.696s sys 0m54.834s $ time ./driver.sh irfan 1000 5 tikras 4m25.145s naudotojas 3m17.286s sys 1m21.490s $ time ./driver.sh brian 1000 5 tikras 0m19.442s naudotojas 0m5.287s sys 0m10.751s $ time ./driver.sh jerry 1000 5 tikras 5m29.136s vartotojas 4m48.926s sys 0m59.336s
31
27 марта '09 в 21:46 2009-03-27 21:46 atsakė Brian Campbell'ui kovo 27 d., 09:21, 2009-03-27 21:46
 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 
13
30 сент. „ DigitalRoss“ atsakymas rugsėjo 30 d 2009-09-30 03:12 '09 3:12 2009-09-30 03:12
 #################################################################### # 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; }' } 

Pavyzdys:

 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 
7
28 июня '11 в 18:28 2011-06-28 18:28 atsakymas duodamas Vadimui birželio 28 d., 11 val. 18:28 2011-06-28 18:28

Bash4 jį iš pradžių palaiko. Nenaudokite grep ar eval , jie yra šliaužčiausios.

Jei norite gauti išsamų išsamų atsakymą su pavyzdiniu kodu, žr. ngn-wiki.ru.site/questions/20275 / ...

5
12 авг. atsakymas, kurį pateikė lhunath 12 rug . 2010-08-12 16:20 '10, 16:20, 2010-08-12 16:20

Dabar atsakykite į šį klausimą.

Šie scenarijai imituoja asociatyvias matricas korpuso scenarijuose. Jo paprasta ir lengvai suprantama.

Žemėlapis yra ne daugiau kaip begalinė eilutė, kurioje keyValuePair įrašoma kaip --name = Irfan - pavadinimas = SSE - company = My: SP: Own: SP: Company

tarpai pakeičiami :: SP: vertėms

 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 

redaguoti: tiesiog pridėjote kitą būdą, kaip ištraukti visus raktus.

 getKeySet() { if [ "$#" != 1 ]; then exit 1; fi mapName=$1; eval map="\"\$$mapName\"" keySet=` echo $map | sed -e "s/=[^ ]*//g" -e "s/\([ ]*\)--/\1/g" ` } 
3
27 марта '09 в 17:07 2009-03-27 17:07 atsakymą pateikė Irfan Zulfiqar, kovo 27 d., 09:17, 2009-03-27 17:07

Galite naudoti dinaminius kintamųjų pavadinimus ir leisti kintamųjų vardams dirbti kaip maišos kortelių raktai.

Pavyzdžiui, jei turite įvesties failą su dviem stulpeliais, pavadinimą, kreditą, kaip parodyta žemiau, ir norite apibendrinti kiekvieno naudotojo pajamas:

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

Toliau pateikta komanda apibendrins viską, naudodama dinaminius kintamuosius raktų pavidalu, žemėlapio _ $ {person} forma:

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

Jei norite skaityti rezultatus:

 set | grep map 

Rezultatai bus:

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

Plėtojant šiuos metodus, aš vystau „ GitHub“ funkciją, kuri veikia taip pat, kaip „HashMap“ objektas, shell_map .

Norėdami sukurti „HashMap“ egzempliorius, „shell_map“ funkcija gali sukurti pačias kopijas pagal skirtingus pavadinimus. Kiekviena nauja funkcijos kopija turės skirtingą $ FUNCNAME kintamąjį. Po to $ FUNCNAME naudojamas kiekvienos žemėlapio egzemplioriaus vardų erdvės kūrimui.

Žemėlapio raktai yra pasauliniai kintamieji, $ FUNCNAME_DATA_ $ KEY, kur $ KEY mygtukas yra raktas, pridėtas prie žemėlapio. Šie kintamieji yra dinaminiai kintamieji .

Bellow Aš pateiksiu supaprastintą versiją, kad galėtumėte ją naudoti kaip pavyzdį.

 #!/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 } 

Taikymas:

 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
03 июня '16 в 11:17 2016-06-03 11:17 atsakymas pateikiamas Bruno Negrão Zicai birželio 13 d. 16 val. 11:17 2016-06-03 11:17

„Bash 3“ yra specialus atvejis, turintis malonų ir paprastą sprendimą:

Jei nenorite dirbti su keliais kintamaisiais arba raktai yra tiesiog negaliojantys kintamojo identifikatoriai, ir jūsų masyvas turi turėti mažiau nei 256 elementus, galite netinkamai naudoti funkcijų grąžinimo reikšmes. Šis sprendimas nereikalauja jokio subshell, nes ši vertė yra lengvai pasiekiama kaip kintamasis arba bet kokia iteracija, kad būtų galima rėkti. Jis taip pat yra labai skaitomas, beveik kaip Bash 4 versija.

Čia yra pagrindinė versija:

 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[$?]} 

Atminkite, kad naudokite atskiras kabutes, priešingu atveju bus taikoma globalizacija. Tikrai naudinga statiniams / užšaldytiems praustuvams nuo pat pradžių, bet jūs galite parašyti indeksų generatorių iš hash_keys=() masyvo.

Saugokitės, pirmasis naudojamas pagal numatytuosius nustatymus, todėl galite pasirinkti nulinį elementą:

 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 

Įspėjimas: ilgis neteisingas.

Arba, jei norite, kad indeksas būtų rodomas nuliniu indeksu, galite rezervuoti kitą indekso vertę ir apsaugoti nuo neegzistuojančio rakto, tačiau tai mažiau suprantama:

 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[$?]} 

Arba, norėdami išlaikyti tinkamą ilgį, perkelkite indeksą vienu:

 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
03 марта '14 в 19:15 2014-03-03 19:15 atsakymas pateikiamas Lloeki kovo 3 d. 14 d. 19.15 val. 2014-03-03 19:15

Gaila, kad aš nemačiau klausimo anksčiau - parašiau karkaso pagrindų biblioteką, kurioje, be kita ko, yra žemėlapiai (asociatyviosios matricos). Naujausią versiją galite rasti čia .

Pavyzdys:

 #!/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
02 марта '11 в 0:29 2011-03-02 00:29 atsakymas pateikiamas Beggy kovo 02 '11, 0:29 2011-03-02 00:29

Manau, kad tai tiesa, kaip jau minėjau, geriausias būdas yra įrašyti / vals raktą į failą, o tada naudokite grep / awk juos ištraukti. Tai skamba kaip bet kokių nereikalingų I / O funkcijų rūšių, bet disko talpykla veikia ir daro jį itin veiksminga - daug greičiau nei bandant juos išsaugoti atmintyje naudojant vieną iš pirmiau minėtų metodų (kaip rodo testai).

Čia yra greitas ir švarus būdas:

 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` 

Jei norite pateikti vieną vertę kiekvienam raktui, taip pat galite atlikti nedidelį grep / sed veiksmą ().

1
09 февр. Atsakymą pateikė Al P. 09 Feb. 2010-02-09 20:19 '10, 20:19, 2010-02-09 20:19

Korpusas neturi integruoto žemėlapio, pvz., Duomenų struktūros, aš naudoju žaliavinę liniją tokiems elementams apibūdinti:

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

ištraukiant elementus ir jų atributus:

 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 

Tai neatrodo protinga, nei kiti žmonės atsako, bet yra lengvai suprantamas naujiems žmonėms už korpusą.

1
05 авг. atsakymas suteiktas 05 rugpjūčio mėn . 2015-08-05 11:38 '15, 11:38, 2015-08-05 11:38

Prieš keletą metų parašiau bash scenarijų biblioteką, kuri palaikė asociatyvias matricas tarp kitų funkcijų (registravimas, konfigūracijos failai, išplėstinė parama komandų eilutės argumentui, pagalba, vieneto testavimas ir kt.). Bibliotekoje yra asociatyvių matricų apvalkalas ir automatiškai persijungia į atitinkamą modelį (vidinis bash4 ir emuliacija ankstesnėms versijoms). Jis buvo vadinamas apvalkalo sistema ir yra prieinamas origo.ethz.ch svetainėje, tačiau šiandien jis yra uždarytas. Jei kas nors vis dar turi, galiu pasidalinti ja su jumis.

0
13 июня '13 в 15:38 2013-06-13 15:38 atsakymą pateikė Beggy, birželio 13 d., „13, 15:38 2013-06-13 15:38

Jūs nežinojote, kokia apvalkalo kalba galite naudoti, taigi galbūt galite apsvarstyti AWK, kuriame yra asociatyvių matricų.

0
29 сент. David R Tribble atsakymas 29 rugsėjis 2009-09-29 22:49 '09, 10:49 PM 2009-09-29 22:49

Vėlinis atsakymas, tačiau taip apsvarstykite problemą, naudodami bash built- read , kaip parodyta sekančiame ufw scenarijaus kodo fragmente. Šio požiūrio privalumas yra kuo daugiau laukų rinkinių (ne tik 2). Mes naudojome separatorių Kadangi uosto diapazono specifikai gali reikėti dvitaškio, ty 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 
0
15 сент. atsakymą pateikė AsymLabs 15 Sep 2015-09-15 18:59 '15 18:59 2015-09-15 18:59

Įrašyta kita parinktis, jei yra jq:

 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
13 июля '18 в 23:11 2018-07-13 23:11 atsakymas pateikiamas pagal kritiką liepos 13 d. 18 val. 11:11 pm 2018-07-13 23:11

Pakeitiau Vadimo tirpalą:

 #################################################################### # 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; }' } 

Pakeitus į map_get, kad būtų išvengta klaidų grąžinimo, jei prašote raktų, kurie neegzistuoja, nors šalutinis poveikis yra tas, kad jis taip pat tyliai ignoruoja trūkstamus žemėlapius, tačiau jis geriau tinka mano naudojimo atvejui, nes tik norėjau patikrinti raktą praleisti elementus kilpoje.

0
11 апр. Atsakymas, kurį pateikė Haravikk Apr 11 2013-04-11 17:22 '13, 17:22 PM 2013-04-11 17:22

Kiti klausimai apie „ žymes arba „ Klauskite“