シェルで地図を作成したいのですが。各値は配列です。したがって、マップはkey:arrayペアです。たとえば、次のようになります。
"Key1" : a1 a2 a3 a4
"key2" : b1 b2 b3
"key3" : c1
基本的に私のコードは次のようになります
listService(){
serviceType=$1
servicesList=($(getServices $serviceType))
}
listService serviceTypeA
listService serviceTypeB
listService serviceTypeC
ここでgetServices
は、$serviceType
として渡された引数に基づいてサービスの配列を返す関数です。したがって、listService
関数を呼び出すたびに、私のserviceList
が新しいサービスリストによって上書きされます。しかし、私は次のようなマップの形で異なるサービスタイプのすべてのサービスを保持したいと思います。
"serviceA" : a1 a2 a3 a4
"serviceB" : b1 b2 b3
"serviceC" : c1
その後、キーに基づいて各アレイにアクセスします。これを達成する方法。
よろしくお願いします。
編集:@cdarkeが提供する答えを試しました。これが私のコードです:
#!/bin/bash
declare -A arrayMap
getValues(){
key=$1
case $key in
AAA )
arr=( AA AAA AAAA )
;;
BBB )
arr=( BB BB BBBB )
;;
CCC )
arr=()
;;
esac
echo "${arr[@]}"
}
fillArrayMap(){
param=$1
values=( $(getValues $param) )
printf "\nIn $param\n"
echo -e "\nArray values is: ${values[@]}\n"
printf "\nLength of the array values is : ${#values[@]}\n"
arrayMap["$param"]=$values #THIS IS THE KEY LINE
valuesList=${arrayMap[$param]}
echo -e "\nArray valuesList is: ${valuesList[@]}\n"
printf "\nLength of the array valuesList is : ${#valuesList[@]}\n"
}
fillArrayMap AAA
fillArrayMap BBB
fillArrayMap CCC
出力から、valuesList
がvalues
配列の最初の要素のみを取得していることがわかります。しかし、私はvaluesList
に、メソッドgetValues
によって返されるすべての要素を含めたいと思います。つまり
valuesList= ${arrayMap[$param]}
valuesList
にはすべての要素が含まれているはずですが、代わりに1つの要素しか含まれていません。それを修正するには?
注:私の目標は、AAAやAAのような個々の要素にアクセスすることです。AAAAA AAAAのような文字列として全体としてそれを必要としません
Bashは多次元配列をサポートしていませんが、多次元配列は必要ないと思います。文字列をリストの形で配列要素に格納できます。これにより、必要なものが得られます。
# My made-up version of getServices
getServices() {
nm="$1"
last=${nm##*Type}
retn=(${last}1 ${last}2 ${last}3 ${last}4)
echo "${retn[@]}"
}
declare -A serviceList
listService(){
serviceType="$1"
# Here I use the key to make an assignment, which adds to the hash
serviceList["$serviceType"]=$(getServices $serviceType)
}
listService serviceTypeA
listService serviceTypeB
listService serviceTypeC
for key in ${!serviceList[@]}
do
echo "\"$key\": ${serviceList[$key]}"
done
与える:
"serviceTypeC": C1 C2 C3 C4
"serviceTypeB": B1 B2 B3 B4
"serviceTypeA": A1 A2 A3 A4
新しい質問の編集:
変更:
arrayMap["$param"]=$values # THIS IS THE KEY LINE
valuesList=${arrayMap[$param]}
に:
arrayMap["$param"]=${values[@]}
valuesList=( ${arrayMap[$param]} )
配列変数をその名前($values
)最初の要素のみを取得します。
Cdarkeが既に述べたように、bash配列は1次元です。長年にわたって、人々は多次元配列を「偽造」する方法を考え出しました。
私が使用した2つの方法は、配列記述の配列を維持する、または他の配列へのポインタの配列を維持することです。前者で答えます。自分で探索したい場合は、後者は明らかです。
以下は、配列のコンテンツが変数の入力に使用される最小限の例です。
#!/usr/bin/env bash
declare -A a=(
[b]='([0]="one" [1]="two")'
[c]='([0]="three" [1]="four")'
)
declare -p a
for key in ${!a[@]}; do
declare -a $key="${a[$key]}"
declare -p $key
done
生成:
declare -A a=([b]="([0]=\"one\" [1]=\"two\")" [c]="([0]=\"three\" [1]=\"four\")" )
declare -a b=([0]="one" [1]="two")
declare -a c=([0]="three" [1]="four")
ここで重要なのは、declare
を使用して$key
の値を参照していることです。これは、bashで$var="value"
とだけ言うことはできないためです。
もちろん、必要がない場合は、変数に$key
の値の名前を付ける必要はありません。たとえば$value
に値を格納すると、$key
で特殊文字を使用できるようになります。
感性を害したり、キー名を制限したりしなければ、さらに単純な代替策は、declare -p
コマンドの出力全体を配列の値に格納し、次にeval
を使用することです。必要なときにそれを。例えば:
declare -A a=(
[b]='declare -a b=([0]="one" [1]="two")'
[c]='declare -a c=([0]="three" [1]="four")'
)
for key in ${!a[@]}; do
eval "${a[$key]}"
done
eval
を嫌う人もいます。 :-)それは残りますが、ツールボックスには残ります。
あなたの場合、完全な [〜#〜] mcve [〜#〜] を提供していないため、アドバイスするのは少し難しいですが、これが私の不自然な例です。
#!/usr/bin/env bash
# contrived getServices function, since you didn't provide one
getServices() {
local -a value=()
local last="${1:$((${#1}-1)):1}" # last character of $1
for n in $( seq 1 $(( $RANDOM / 8192 + 1 )) ); do
value+=(${last}${n})
done
declare -p value # output of this function is actual bash code.
}
# populate the array
listService() {
servicesList[$1]=$( getServices $1 )
}
# Initialize this as empty to make `eval` safer
declare -A servicesList=()
# These services seem interesting.
listService serviceA
listService serviceB
listService serviceC
# Note that we're stepping through KEYS here, not values.
for row in "${!servicesList[@]}"; do
printf '"%s": ' "$row"
eval "${servicesList[$row]}" # Someone is bound to complain about this.
for column in "${!value[@]}"; do
# Add whatever $row and $column specific code you like here.
printf '%s ' "${value[$column]}"
done
printf "\n"
done
私の出力:
$ bash 2dimarrayexample
"serviceC": C1
"serviceB": B1 B2 B3 B4
"serviceA": A1 A2
もちろん、getServicesはランダムな出力を生成するため、出力は異なる場合があります。 :)