2017-01-16 4 views
4

シェルでマップを作成したいと思います。各値は配列です。したがって、マップはキーです:配列のペア。例えばそれは、このようなことができます:キーのマップを作成するには:shellの配列ですか?

"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 

私はvaluesListvalues配列の最初の要素だけを取得して見ることができます。しかし、valuesListには、getValuesというメソッドで返されたすべての要素が含まれています。すなわち

valuesList= ${arrayMap[$param]} 

valuesListは、今では1つだけの要素が含まれている代わりに、すべての要素が含まれている必要があります。それを修正するには?

注:私の目標は、AAAまたはAAのような個々の要素にアクセスすることで、私はbashは多次元配列をサポートしていますが、私はありません

+0

gawkは2次元配列を持っています(実際にはhastableでインプリメントされています)。 – Kent

+1

であなたの他のロジックをドラッグするかawkを使うことが考えられます。 ;-) – Kent

答えて

3

AA AAA AAAAのような文字列として、全体としてそれを必要としませんあなたが1つ必要とは思わない。文字列を配列要素にリストの形式で格納することができます。これにより、要求する内容が得られます。

# 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 

EDIT:

を変える:

arrayMap["$param"]=$values  # THIS IS THE KEY LINE 
valuesList=${arrayMap[$param]} 

へ:

arrayMap["$param"]=${values[@]} 
valuesList=(${arrayMap[$param]} ) 

配列変数を名前($values)だけで参照すると、最初の要素はになります。

+0

あなたの答えをありがとう。私は別の問題を試してみました。質問の詳細に同じものを追加しました。あなたは何かを提案してもらえますか? – saurav

2

すでに述べたように、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、あなたはちょうど$var="value"とbashで言うことはできません。

もちろん、望ましくない場合は、変数名に$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 

Some people don't like 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がランダム出力を生成するので、あなたの出力は、異なる場合があります。 :)

+0

なぜ 'listService'を実行した順番とは異なる順序で出力されますか?また、このように 'eval'を使うことに伴うリスクは何ですか?非常に微妙でなければならない、私はそれを全く見ない。 – Graham

+1

@Graham - 連想配列はbashで順番に保持されません。順序を保持する必要がある場合は、連想配列内のキーを指し示す別々の非連想(番号付き)配列を維持し、順序を保証するために 'for'ループを使用して2番目の配列をステップします。 – ghoti

関連する問題