访问bash数组键(mac)

时间:2012-04-11 15:56:50

标签: macos bash unix

由于某种原因,我无法使用感叹号语法访问数组键:

declare -a sites
sites=(["fr"]="frederick" ["an"]="annapolis")

for i in "${!sites[@]}"
  do
    echo "key: $i "
  done

这只是回声"键:0"

我在这里做错了什么?

另外,我想添加值。

所以我们的看法是:

key:fr,value:frederick

3 个答案:

答案 0 :(得分:0)

问题是declare -a

根据手册页,它应该是declare -A

declare [-aAfFgilrtux] [-p] [name[=value] ...]
    ...
    -a     Each name is an indexed array variable (see Arrays above).
    -A     Each name is an associative array variable (see Arrays above).

请改为尝试:

declare -A sites
sites=(["fr"]="frederick" ["an"]="annapolis")

for i in "${!sites[@]}"
  do
    echo "key: $i, value: ${sites[$i]}"
  done

答案 1 :(得分:0)

可以在旧的bash版本中完成。

在较早版本的bash中,您可以使用整个环境变量集来实现关联数组(也称为哈希)

export HASH_PREFIX="I_AM_A_HASH"

hash-set() {
    HASH_NAME="$1" ; shift
    HASH_KEY="$1"  ; shift
    HASH_VAL="$1"  ; shift
    eval "export ${HASH_PREFIX}_${HASH_NAME}_KEY_${HASH_KEY}='$HASH_VAL'"
}
hash-get() {
    HASH_NAME="$1" ; shift
    HASH_KEY="$1"  ; shift
    eval "echo \"\$${HASH_PREFIX}_${HASH_NAME}_KEY_${HASH_KEY}\""
}
hash-keys() {
    HASH_NAME="$1" ; shift
    HASH_PREFIX_NAME_LENGTH=$(( ${#HASH_PREFIX} + ${#HASH_NAME} + 6 ))
    declare -x | while read -r LINE_READ ; do
        LINE_READ="${LINE_READ:11}"
        if [   x"${LINE_READ:0:HASH_PREFIX_NAME_LENGTH}" \
             = x"${HASH_PREFIX}_${HASH_NAME}_KEY_" \
           ]
        then
            LINE_READ="${LINE_READ:HASH_PREFIX_NAME_LENGTH}"
            LINE_READ="${LINE_READ/=*/}"
           echo "${LINE_READ}"
        fi
    done
}

hash-set sites "fr" "frederick"
hash-set sites "an" "annapolis"

for i in $(hash-keys sites) ; do
    echo "key: $i, value: $(hash-get sites $i)"
done

这些键只能与环境变量(0-9,a-z,A-Z,_)使用相同的字符。

您可以通过使用“ _xx”来表示非字母数字的ascii值来解决(例如,“ _”的示例为“ _5f”,“?”的示例为“ _3f”)。 rosettacode具有如何在纯字符中在ASCII字符和十六进制之间来回转换。

另外,在Mac笔记本电脑上,您可以安装homebrew,然后使用它来安装更新的bash。 您也可以在awk或perl或ruby或python中使用完整的关联数组。

答案 2 :(得分:0)

我认为可能缺少大写字母...

declare -A _sites=( ["fr"]="frederick" ["an"]="annapolis" )

for i in "${!_sites[@]}"; do
    printf '%s -> %s\n' "${i}" "${_sites[$i]}"
done

有助于整理上述内容的资源不限于以下内容;

  • @anubhava关于declare -A使用情况的答案

  • 来自@lhunath的答案也涵盖了针对Bash版本3或更低版本的解决方法。

  

在阅读了其他已发布答案的评论后,我认为如果卡在较旧版本的Bash中而无法更新原因,那么您将希望使用上一个列出的答案的解决方法。


@Fenn还有一些笔记...

hash-set() {
    HASH_NAME="$1" ; shift
    HASH_KEY="$1"  ; shift
    HASH_VAL="$1"  ; shift
    eval "export ${HASH_PREFIX}_${HASH_NAME}_KEY_${HASH_KEY}='$HASH_VAL'"
}

...如果没有shifteval,并且带有必需的参数,则可能看起来像...

hash_set(){
    local _name="${1:?${FUNCNAME[0]} not provided a Hash Name}"
    local _key="${2:?${FUNCNAME[0]} not provided a Hash Key}"
    local _value="${3:?${FUNCNAME[0]} not provided a Value}"
    declare -g "${HASH_PREFIX}_${_name}_KEY_${_key}='${_value}'"
}

...希望这对于将答案转化为可以投票的内容有帮助。