web-dev-qa-db-ja.com

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

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

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

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

11
EggHead

連想配列を持つシェル

最近のシェルの中には、連想配列を提供するものがあります: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では、keysと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"
}
_

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

ストアの意味がわかりませんが、${!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

私はこれについてニースの短いチュートリアルを見つけました here


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

5
terdon

連想配列のないシェル

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

コツは、配列に保存する代わりに[$ key]、変数に保存するarray_$ key

セットする:

eval "array_$key='$value'"

取得する:

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

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

0
Marián Černý