Bash检查变量是否为数组

wuj*_*jek 30 arrays bash

我有一个变量名循环,我需要检查该名称指向的变量是否是一个数组.我试图谷歌,但没有找到任何东西.有帮助吗?

for varname in AA BB CC; do
  local val
  if [ "$varname" is array ]; then # how can I perform this test?
    echo do something with an array
  else
    echo do something with a "'normal'" variable
  fi
done
Run Code Online (Sandbox Code Playgroud)

小智 33

为避免调用grep,您可以使用:

if [[ "$(declare -p variable_name)" =~ "declare -a" ]]; then
    echo array
else
    echo no array
fi
Run Code Online (Sandbox Code Playgroud)

  • 评论多个答案:如果你更新你的正则表达式也检查'排版'而不仅仅是'声明',这将更加便携. (4认同)

Bas*_*sen 16

谷歌可能是你的朋友:

declare -p variable-name 2> /dev/null | grep -q '^declare \-a'
Run Code Online (Sandbox Code Playgroud)

  • 谷歌是我的朋友,这就是他带我到这里的原因.(这也是因为他是SO的朋友.) (18认同)
  • 一个更快的选择:`str="\`declare -p astr 2>/dev/null\`";if [[ "${str:0:10}" == 'declare -a' ]];then echo array ;fi` 我想知道有没有更快的东西? (2认同)

Mar*_*rco 10

从bash 4.3开始,它就不那么容易了.

使用"declare -n",您可以添加对另一个变量的引用,您可以一遍又一遍地执行此操作.好像这不够复杂,使用"declare -p",你不会得到类型或原始变量.

例:

$ declare -a test=( a b c d e)
$ declare -n mytest=test
$ declare -n newtest=mytest
$ declare -p newtest
declare -n newtest="mytest"
$ declare -p mytest
declare -n mytest="test"
Run Code Online (Sandbox Code Playgroud)

因此,您必须遍历所有引用.在bash中,这将是这样的:

vartype() {
    local var=$( declare -p $1 )
    local reg='^declare -n [^=]+=\"([^\"]+)\"$'
    while [[ $var =~ $reg ]]; do
            var=$( declare -p ${BASH_REMATCH[1]} )
    done

    case "${var#declare -}" in
    a*)
            echo "ARRAY"
            ;;
    A*)
            echo "HASH"
            ;;
    i*)
            echo "INT"
            ;;
    x*)
            echo "EXPORT"
            ;;
    *)
            echo "OTHER"
            ;;
    esac
}
Run Code Online (Sandbox Code Playgroud)

通过上面的例子:

$ vartype newtest
ARRAY
Run Code Online (Sandbox Code Playgroud)

要检查数组,可以修改代码或将其与grep一起使用:

vartype $varname | grep -q "ARRAY"
Run Code Online (Sandbox Code Playgroud)


mik*_*n32 5

我从上面鲁本的精彩回答开始。我实施了一些评论和我自己的一些改进,并得出了以下结论:

#!/bin/bash
array_test() {
    # no argument passed
    [[ $# -ne 1 ]] && echo 'Supply a variable name as an argument'>&2 && return 2
    local var=$1
    # use a variable to avoid having to escape spaces
    local regex="^declare -[aA] ${var}(=|$)"
    [[ $(declare -p "$var" 2> /dev/null) =~ $regex ]] && return 0
}
Run Code Online (Sandbox Code Playgroud)

现在我可以这样做:

foo=(lorem ipsum dolor)
bar="declare -a tricky"
declare -A baz

array_test foo && echo "it's an array"
array_test bar && echo "it's an array"
# properly detects empty arrays
array_test baz && echo "it's an array"
# won't throw errors on undeclared variables
array_test foobarbaz && echo "it's an array"
Run Code Online (Sandbox Code Playgroud)