检查是否存在关联数组

时间:2019-12-12 12:12:06

标签: bash

bash 4.2起,添加了-v条件表达式。它用于检查是否设置了变量(已分配值)。当编写在set -o nounset下运行的脚本时,这是一个有用的工具,因为尝试使用未初始化的变量会导致错误。

我有一个问题,请参见POSIX bashset -o posix)中的示例:

$ declare testvar=0
$ [ -v testvar ] && echo "It works!"
It works!
$ declare -A fizz=( [buzz]=jazz )
$ [ -v fizz[buzz] ] && echo "It works!"
It works!
$ [ -v fizz ] && echo "It doesn't work :("
$ 

如您所见,对常规变量使用-v可以正常工作。使用它来检查关联数组中字段的存在也可以正常工作。但是,在检查关联数组本身的存在时,它不起作用。

那是为什么,并且有解决方法吗?

2 个答案:

答案 0 :(得分:1)

如果您想知道它是否有任何条目,可以检查${#fizz[@]},但这并不能告诉您它是否被创建为空。您可以 将case语句或其他模式匹配与错误检查结合使用。

tst() { local tst;   
  (( $# )) || return                             # *minimal* error handling...
  if tst="$(declare -p $1 2>&1)"                 # does the subshell error?
  then case "$tst" in                            # if not, check the output
       *\)*) (( $( eval echo \${#$1[@]} ) )) &&  # test number of entries
                echo "Has Args"              ||  # some implementations show '()'
                echo "Empty but defined";;       # some don't; this is for the *do*
       *-A*) echo "Empty but defined";;          # this is for the don't
          *) echo ERROR;;                        # shouldn't get here
       esac
  else echo Undefined                            # if doesn't exist
  fi
}


$: unset fizz
$: tst fizz
Undefined
$: declare -A fizz
$: tst fizz
Empty but defined
$: fizz[buzz]=jazz
$: tst fizz
Has Args

唐诺(Dunno)在您的上下文中有多大用处。 请注意,我是为关联数组显式编写的,它具有与该点不直接相关的最小错误检查。对于任何实际生产用途,都应该扩展很多。

我不喜欢eval,但是我的bash版本没有名称引用。 :o /

答案 1 :(得分:0)

严格检查 varname 是否作为关联数组存在:

check4Associative() {
    local foo typ
    read foo typ foo < <(declare -p $1 2>&1)
    [ "$typ" ] && [ -z "${typ//-*A*}" ]
}

您可以用作:

if check4Associative myVar; then ... ;fi

示例尝试:

unset fizz
check4Associative fizz && echo yes;echo $?
1

fizz=Blah
check4Associative fizz && echo yes;echo $?
1

declare -A fizz
check4Associative fizz && echo yes;echo $?
yes
0

fizz[foo]=bar
check4Associative fizz && echo yes;echo $?
yes
0

再走一步:条目数:

check4AssociativeArgs() {
    local -n var=$1
    local keys=(${!var[@]}) foo typ
    read foo typ foo < <(declare -p $1 2>&1)
    [ "$typ" ] && [ -z "${typ//-*A*}" ] &&
        printf "Name: %s, type: %s, entry count: %d\n" $1 ${typ#-} ${#keys[@]}
}

然后

unset fizz
check4AssociativeArgs fizz ; echo $?
1

declare -A fizz
check4AssociativeArgs fizz
Name: fizz, type: A, entry count: 0

fizz[foo]=bar fizz[bar]=baz
check4AssociativeArgs fizz
Name: fizz, type: A, entry count: 2