【问题标题】:Accessing bash array keys (mac)访问 bash 数组键 (mac)
【发布时间】:2012-04-11 15:56:50
【问题描述】:

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

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

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

这只是回显“key : 0”

我在这里做错了什么?

另外,我想添加值。

所以我们的 put 是:

键:fr,值:弗雷德里克

【问题讨论】:

    标签: macos bash unix


    【解决方案1】:

    可以在旧的 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 有如何在纯 bash 中在 ascii 字符和十六进制之间来回转换。

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

    【讨论】:

    • 请不要不要使用eval,而是参阅@lhunath 的解决方法,了解早于4 的Bash 版本。
    【解决方案2】:

    问题是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
    

    【讨论】:

    • 那是我一开始尝试的。但是,如果我运行您发布的脚本,我会得到以下输出:第 3 行:声明:-A:无效选项声明:用法:声明 [-afFirtx] [-p] [name[=value] ...] key: 0 , 值:安纳波利斯
    • 这可能也有帮助:bash --version GNU bash,版本 3.2.48(1)
    • 关联数组需要 bash >= 4.0。见tiswww.case.edu/php/chet/bash/NEWS。而且您的 bash 3.2 手册页没有说明关联数组的任何内容。 ;-)
    • @Mikel,该问题被标记为macos,除非采取“特殊措施”(如macportsbrew),否则它始终是bash 3.2。
    【解决方案3】:

    我认为这可能是缺少大写的阻碍......

    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 或更低版本的解决方法。

    在阅读了其他发布的答案的 cmets 之后,我认为如果您遇到无法更新的旧版 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'"
    }
    

    ...没有shifting 或eval,并且带有必需的参数可能看起来像...

    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}'"
    }
    

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

    【讨论】:

      猜你喜欢
      • 2023-03-05
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 2013-02-11
      • 1970-01-01
      • 2019-03-02
      相关资源
      最近更新 更多