bash で連想配列

どうしてもシェルで連想配列が使いたければ zsh でも使えばいいんでしょうが、修行の一環として bash で連想配列もどきを作ってみました。

※追記
bash 4.0 から連想配列が導入されたみたいです。が、キーの一覧を取得する方法が見当たりません。declare -p で連想配列の中身を見ることはできますが、厳しいです。詳細は info bash を見て下さい。

以前 “ゲームで極める シェルスクリプトスーパーテクニック” という本を読んだんですが、そこで確か配列を eval の力で実装してたと思います。それが基になってます。

#!/bin/bash

array_get_index () {
    if [ $# -ne 2 ]; then
        echo "usage: array_get_index array val"
        exit 1
    fi

    local len
    eval 'len=${#'"$1"'[@]}'

    for ((i = 0; i < $len; ++i)); do
        eval test 'x${'"$1"'[$i]}' = x"$2"

        if [ $? -eq 0 ]; then
            echo -n "$i"
            return 0
        fi
    done
}

hash_set () {
    if [ $# -ne 3 ]; then
        echo "usage: hash_set hash key val"
        exit 1
    fi

    local keys_var='myhash_'"$1"'_keys'

    eval "$keys_var"'[${#'"$keys_var"'[@]}]='"$2"
    eval 'myhash_'"${1}_$2"'='"$3"
}

hash_get () {
    if [ $# -ne 2 ]; then
        echo "usage: hash_get hash key"
    fi

    eval echo -n '$myhash_'"${1}_$2"
}

hash_len () {
    if [ $# -ne 1 ]; then
        echo "usage: hash_len hash"
    fi

    eval echo -n '${#myhash_'"$1"'_keys[@]}'
}

hash_del () {
    if [ $# -ne 2 ]; then
        echo "usage: hash_del hash key"
    fi

    local index

    eval 'index=$(array_get_index myhash_'"$1"'_keys '"$2"')'

    unset 'myhash_'"${1}_$2"

    if [ x"$index" != x ]; then
        unset 'myhash_'"$1"'_keys['"$index"']'
    fi
}

hash_keys () {
    if [ $# -ne 1 ]; then
        echo "usage: hash_keys hash"
        exit 1
    fi

    eval echo -n '${myhash_'"$1"'_keys[@]}'
}

hash_set "capital" "tokyo" "shinjuku"
hash_set "capital" "kanagawa" "yokohama"
hash_set "capital" "saitama" "saitama"

echo "$(hash_len 'capital')"

for key in $(hash_keys "capital"); do
    printf "%-8s : %s\n" "$key" "$(hash_get capital $key)"
done

hash_del "capital" "kanagawa"

echo "$(hash_len 'capital')"

for key in $(hash_keys "capital"); do
    printf "%-8s : %s\n" "$key" "$(hash_get capital $key)"
done

hash_ なんてプレフィックスが付いてるくせに、ハッシュ関係ありません。ひどい話です。

下は実行結果です:


3
tokyo    : shinjuku
kanagawa : yokohama
saitama  : saitama
2
tokyo    : shinjuku
saitama  : saitama

(コウヅ)

広告

bash で連想配列」への2件のフィードバック

  1. bash 4.x で echo ${!BASH_ALIASES[@]} をためしてください。
    ちなみにこの記事の方法ではなく hash 組み組みコマンドを悪用する方法もあります

    prefix=”:hoge:”
    hash=”myhash:”
    hash -p “$prefix$value” “$prefix$hash$key” # set
    hash -t “$prefix$hash$key” # get
    hash -l # iter, kets, values …

    • !? ${!BASH_ALIASES[@]} なんていう機能があったんですか。無いのはおかしいと思っていましたが…。
      そして hash コマンドを使う方法、クールなトリックですね!Mac のデフォルトの bash はバージョン 3 なので、活躍しそうです。
      情報ありがとうございます!

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中