シェルスクリプトの連想配列


11

連想配列をシェルスクリプトに実装するトリックを見ました。たとえば、key = apples print array["apples"]としてスクリプト化できますecho \$array$key

ただし、配列を反復処理するためのキーを生成する方法については言及されていません。スペースで区切られた変数にキーを格納して、forループを使用して配列を反復できるようにすることしか考えられませんでした。

それで、後で使用するためにキーを格納する他の方法はありますか?


5
シェルスクリプトで連想配列を使用しようとしている場合、プロジェクトがシェルスクリプトには複雑すぎる可能性があります。:)
Martin von Wittich

@MartinvonWittichなんで?3つの可能なDBスキーマの1つでSQLスクリプトを実行するシェルスクリプトがあります。必要なスキーマは、省略形でファイル名に含まれています。この省略形と実際のスキーマ名の間のマッピングが必要です。実際のスキーマ名(省略形ではない)は環境によって異なる可能性があるため、連想配列よりも優れた方法であり、配列変数(値を一度だけ設定できる)は完璧です
Slav

2
@Slav私は連想配列に対してではなく、そのような複雑さが必要なシェルスクリプトに対してだけ議論しています。しかし、それは私の個人的な好みにすぎません。シェルスクリプトを書き始めて、特定の複雑さのしきい値を超えていることに気づいたらすぐにPerlでそれを書き直すことがよくあります。
Martin von Wittich、2014年

回答:


20

連想配列を持つシェル

最近のシェルの中には、連想配列を提供するものがあります:ksh93、bash≥4、zsh。ksh93とbashでは、aが連想配列の場合、"${!a[@]}"はそのキーの配列です。

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

zshでは、その構文はkshエミュレーションモードでのみ機能します。それ以外の場合は、zshのネイティブ構文を使用する必要があります。

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}a空のキーがない場合にも機能します。

zshでは、keyとvaluesの両方を同時にループすることもできます。

for k v ("${(@kv)a}") echo "$k -> $v"

連想配列のないシェル

連想配列を持たないシェルで連想配列をエミュレートすることは、はるかに多くの作業です。連想配列が必要な場合は、ksh93やPerlなどのより大きなツールを導入するときがきました。

単なるPOSIXシェルで連想配列が必要な場合は、キーが文字0-9A-Z_a-z(ASCII数字、文字、アンダースコア)のみを含むように制限されている場合に、それらをシミュレートする方法を次に示します。この仮定の下で、キーは変数名の一部として使用できます。以下の関数は、2つの連続するアンダースコアを含んではならない「stem」という名前の接頭辞で識別される配列に作用します。

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(警告、テストされていないコード。構文的に無効なステムおよびキーのエラー検出は提供されていません。)


5

ストアの意味がわかりませんが、次の${!array[@]}構文を使用してキーを反復できます。

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

したがって、反復するには:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

私はここにこれについての良い、短いチュートリアルを見つけました。


以下のコメントで指摘されているように、連想配列はbashバージョン4で追加されました。この件に関するLinuxジャーナルの記事については、こちらを参照してください。


1
(bash version 4 only)これは重要なことです。従来、bash配列は数値のみです。
リッキービーム

1
例のtypeset代わりに使用したい場合がdeclareあります。それはそれらを最初にシェル連想配列を実装したbash 4とksh93の間で移植可能にするでしょう。
jlliagre 2014年

0

連想配列のないシェル

キーが[0-9A-Za-z_](数字、文字、アンダースコア)に制限されている場合はそれほど難しくありません。

コツはarray [ $ key ] に保存する代わりに、変数array_ $ keyに保存することです。

セットする:

eval "array_$key='$value'"

取得する:

value=`eval echo '$'array_$key`

注:値に'(一重引用符)を含めることはできません。


-1

これはbashで動作します

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

または

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

eval afaikを使用する必要はありません


1
私はあなたが質問の要点を逃したと信じています。
G-Manは 'Reinstate Monica'を
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.