【问题标题】:How to test if an array key is present in Bash 4.2?如何测试 Bash 4.2 中是否存在数组键?
【发布时间】:2012-11-02 18:13:16
【问题描述】:

我得出的最接近的解决方案是:

declare -A foobar=([foo]=bar [bar]=foo)
(set -u; true ${foobar[foo]}) 2>/dev/null

理想情况下,我想使用test -v 来测试是否定义了数组键。但是test -v foobar[bar] 显然总是返回1。此外,我不想要全局 set +u 并冒着访问未定义变量的风险。

【问题讨论】:

    标签: bash associative-array


    【解决方案1】:
    keys=" ${!foobar[*]} "
    wanted=foo
    if [[ $keys == *" $wanted "* ]]; then
        echo "foobar contains key $wanted"
    else
        echo "key $wanted not present"
    fi
    

    如果键可能包含空格,或者如果想要的键恰好是“bar foo”或连续键的某种组合,这可能会失败。

    更新: 这可能效率较低,但它既安全(空白)又更清晰:

    for key in "${!foobar[@]}"; do
        if [[ $key = $wanted ]]; then
            echo "foobar contains key $wanted"
            break
        fi
    done
    

    【讨论】:

    • 首先感谢您的回答。但我发现你的方法不仅不那么富有表现力,而且更脆弱,因为你已经暗示了两个诱杀装置。
    【解决方案2】:

    从 bash 版本“4.2.39(1)-release”开始,我看不到如何使用 test -v 命令测试数组键是否存在。 test -v foobar[foo] 总是失败。对我来说,最好的选择似乎应该使用${foobar[foo]-bar} 参数替换进行测试。为了使用 shopt 的 nounset shell 选项和每个新版本重新测试 Bash 的行为,我编写了以下 Bash shell 脚本:

    #!/bin/bash
    
    shopt -os nounset
    
    declare -ri colors=1
    if (( "$colors" )); then
      declare -r bold="\e[1m"
      declare -r red="\e[41m"
      declare -r green="\e[42m"
      declare -r end="\e[0;m"
    else
      declare -r bold=
      declare -r red=
      declare -r green=
      declare -r end=
    fi
    declare -ri a="${1:-0}"
    case "$a" in
      1)
        echo -e "$a. Accessing ${bold}\"\$foobar\"${end} when unset should result in an error."
        echo "$foobar"
        ;;
      2)
        echo -e "$a. Accessing ${bold}\"\${foobar-bar}\"${end} when unset should result in the \"bar\" default value."
        echo "${foobar-bar}"
        ;;
      3)
        echo -e "$a. Accessing ${bold}\"\${foobar:-bar}\"${end} when unset should result in the \"bar\" default value."
        echo "${foobar:-bar}"
        ;;
      4)
        echo -e "$a. Accessing ${bold}\"\$foobar\"${end} when set to the NULL string should result in it (whitespace)."
        declare -r foobar=
        echo "$foobar"
        ;;
      5)
        echo -e "$a. Accesssing ${bold}\"\${foobar-bar}\"${end} when set to the NULL string should result in it (whitespace)."
        declare -r foobar=
        echo "${foobar-bar}"
        ;;
      6)
        echo -e "$a. Accesssing ${bold}\"\${foobar:-bar}\"${end} when set to the NULL string should result in the \"bar\" default value."
        declare -r foobar=
        echo "${foobar:-bar}"
        ;;
      7)
        echo -e "$a. Accessing ${bold}\"\$foobar\"${end} when set to the \"foo\" string should result in it."
        declare -r foobar=foo
        echo "$foobar"
        ;;
      8)
        echo -e "$a. Accessing ${bold}\"\${foobar-bar}\"${end} when set to the \"foo\" string should result in it."
        declare -r foobar=foo
        echo "${foobar-bar}"
        ;;
      9)
        echo -e "$a. Accessing ${bold}\"\${foobar:-bar}\"${end} when set to the \"foo\" string should result in it."
        declare -r foobar=foo
        echo "${foobar:-bar}"
        ;;
      10)
        echo -e "$a. Accessing ${bold}\"\${foobar[foo]}\"${end} when unset should result in an error."
        declare -rA foobar=()
        echo "${foobar[foo]}"
        ;;
      11)
        echo -e "$a. Accessing ${bold}\"\${foobar[foo]-bar}\"${end} when unset should result in the \"bar\" default value."
        declare -rA foobar=()
        echo "${foobar[foo]-bar}"
        ;;
      12)
        echo -e "$a. Accessing ${bold}\"\${foobar[foo]:-bar}\"${end} when unset should result in the \"bar\" default value."
        declare -rA foobar=()
        echo "${foobar[foo]:-bar}"
        ;;
      13)
        echo -e "$a. Accessing ${bold}\"\${foobar[foo]}\"${end} when set to the NULL string should result in it (whitespace)."
        declare -rA foobar=([foo]=)
        echo "${foobar[foo]}"
        ;;
      14)
        echo -e "$a. Accessing ${bold}\"\${foobar[foo]-bar}\"${end} when set to the NULL string should result in it (whitespace)."
        declare -rA foobar=([foo]=)
        echo "${foobar[foo]-bar}"
        ;;
      15)
        echo -e "$a. Accessing ${bold}\"\${foobar[foo]:-bar}\"${end} when set to the NULL string should result in the \"bar\" default value."
        declare -rA foobar=([foo]=)
        echo "${foobar[foo]:-bar}"
        ;;
      16)
        echo -e "$a. Testing with ${bold}\"test -v foobar\"${end} when unset should fail."
        test -v foobar
        ;;
      17)
        echo -e "$a. Testing with ${bold}\"test -v foobar\"${end} when set to the NULL string should succeed."
        declare -r foobar=
        test -v foobar
        ;;
      18)
        echo -e "$a. Testing with ${bold}\"test -v foobar\"${end} when set to the \"bar\" string should succeed."
        declare -r foobar=
        test -v foobar
        ;;
      19)
        echo -e "$a. Testing with ${bold}\"test -v foobar[foo]\"${end} when unset should fail."
        declare -rA foobar=()
        test -v foobar[foo]
        ;;
      20)
        echo -e "$a. Testing with ${bold}\"test -v foobar[foo]\"${end} when set to the NULL string should fail."
        declare -rA foobar=([foo]=)
        test -v foobar[foo]
        ;;
      21)
        echo -e "$a. Testing with ${bold}\"test -v foobar[foo]\"${end} when set to the \"bar\" string should succeed."
        declare -rA foobar=([foo]=bar)
        test -v foobar[foo]
        ;;
      0)
        echo -e "Testing shopt's \"nounset\" shell option with Bash version \"$BASH_VERSION\"."
        echo
        declare -i b
        for ((b=1; b<=21; b+=1)); do
          "$0" "$b"
          if (( "$?" )); then
            echo -e "${red}Failure.${end}"
          else
            echo -e "${green}Success.${end}"
          fi
          echo
        done
        ;;
    esac
    

    【讨论】:

      猜你喜欢
      • 2011-09-07
      • 1970-01-01
      • 2020-04-11
      • 1970-01-01
      • 2015-01-11
      • 1970-01-01
      • 2010-10-22
      相关资源
      最近更新 更多