Easiest way to check for an index or a key in an array?

后端 未结 7 1690
小鲜肉
小鲜肉 2020-12-02 07:30

Using:

set -o nounset
  1. Having an indexed array like:

    myArray=( "red" "black" "blue" )
    
    
            
相关标签:
7条回答
  • 2020-12-02 07:39

    To check if the element is set (applies to both indexed and associative array)

    [ ${array[key]+abc} ] && echo "exists"
    

    Basically what ${array[key]+abc} does is

    • if array[key] is set, return abc
    • if array[key] is not set, return nothing


    References:

    1. See Parameter Expansion in Bash manual and the little note

      if the colon is omitted, the operator tests only for existence [of parameter]

    2. This answer is actually adapted from the answers for this SO question: How to tell if a string is not defined in a bash shell script?


    A wrapper function:

    exists(){
      if [ "$2" != in ]; then
        echo "Incorrect usage."
        echo "Correct usage: exists {key} in {array}"
        return
      fi   
      eval '[ ${'$3'[$1]+muahaha} ]'  
    }
    

    For example

    if ! exists key in array; then echo "No such array element"; fi 
    
    0 讨论(0)
  • 2020-12-02 07:39

    This is the easiest way I found for scripts.

    <search> is the string you want to find, ASSOC_ARRAY the name of the variable holding your associative array.

    Dependign on what you want to achieve:

    key exists:

    if grep -qe "<search>" <(echo "${!ASSOC_ARRAY[@]}"); then echo key is present; fi
    

    key exists not:

    if ! grep -qe "<search>" <(echo "${!ASSOC_ARRAY[@]}"); then echo key not present; fi
    

    value exists:

    if grep -qe "<search>" <(echo "${ASSOC_ARRAY[@]}"); then echo value is present; fi
    

    value exists not:

    if ! grep -qe "<search>" <(echo "${ASSOC_ARRAY[@]}"); then echo value not present; fi
    
    0 讨论(0)
  • 2020-12-02 07:42

    From man bash, conditional expressions:

    -v varname
                  True if the shell variable varname is set (has been assigned a value).
    

    example:

    declare -A foo
    foo[bar]="this is bar"
    foo[baz]=""
    if [[ -v "foo[bar]" ]] ; then
      echo "foo[bar] is set"
    fi
    if [[ -v "foo[baz]" ]] ; then
      echo "foo[baz] is set"
    fi
    if [[ -v "foo[quux]" ]] ; then
      echo "foo[quux] is set"
    fi
    

    This will show that both foo[bar] and foo[baz] are set (even though the latter is set to an empty value) and foo[quux] is not.

    0 讨论(0)
  • 2020-12-02 07:47

    tested in bash 4.3.39(1)-release

    declare -A fmap
    fmap['foo']="boo"
    
    key='foo'
    # should echo foo is set to 'boo'
    if [[ -z "${fmap[${key}]}" ]]; then echo "$key is unset in fmap"; else echo "${key} is set to '${fmap[${key}]}'"; fi
    key='blah'
    # should echo blah is unset in fmap
    if [[ -z "${fmap[${key}]}" ]]; then echo "$key is unset in fmap"; else echo "${key} is set to '${fmap[${key}]}'"; fi
    
    0 讨论(0)
  • 2020-12-02 07:49

    New answer

    From version 4.2 of bash (and newer), there is a new -v option to built-in test command.

    From version 4.3, this test could address element of arrays.

    array=([12]="red" [51]="black" [129]="blue")
    
    for i in 10 12 30 {50..52} {128..131};do
        if [ -v array[i] ];then
            echo "Variable 'array[$i]' is defined"
        else
            echo "Variable 'array[$i]' not exist"
        fi
    done
    Variable 'array[10]' not exist
    Variable 'array[12]' is defined
    Variable 'array[30]' not exist
    Variable 'array[50]' not exist
    Variable 'array[51]' is defined
    Variable 'array[52]' not exist
    Variable 'array[128]' not exist
    Variable 'array[129]' is defined
    Variable 'array[130]' not exist
    Variable 'array[131]' not exist
    

    This work with associative arrays in same way:

    declare -A aArray=([foo]="bar" [bar]="baz" [baz]=$'Hello world\041')
    
    for i in alpha bar baz dummy foo test;do
        if [ -v aArray[$i] ];then
            echo "Variable 'aArray[$i]' is defined"
        else
            echo "Variable 'aArray[$i]' not exist"
        fi
    done
    Variable 'aArray[alpha]' not exist
    Variable 'aArray[bar]' is defined
    Variable 'aArray[baz]' is defined
    Variable 'aArray[dummy]' not exist
    Variable 'aArray[foo]' is defined
    Variable 'aArray[test]' not exist
    

    With a little difference:
    In regular arrays, variable between brackets ([i]) is integer, so dollar symbol ($) is not required, but for associative array, as key is a word, $ is required ([$i])!

    Old answer for bash prior to V4.2

    Unfortunately, bash give no way to make difference betwen empty and undefined variable.

    But there is some ways:

    $ array=()
    $ array[12]="red"
    $ array[51]="black"
    $ array[129]="blue"
    
    $ echo ${array[@]}
    red black blue
    
    $ echo ${!array[@]}
    12 51 129
    
    $ echo "${#array[@]}"
    3
    
    $ printf "%s\n" ${!array[@]}|grep -q ^51$ && echo 51 exist
    51 exist
    
    $ printf "%s\n" ${!array[@]}|grep -q ^52$ && echo 52 exist
    

    (give no answer)

    And for associative array, you could use the same:

    $ unset array
    $ declare -A array
    $ array["key1"]="red"
    $ array["key2"]="black"
    $ array["key3"]="blue"
    $ echo ${array[@]}
    blue black red
    
    $ echo ${!array[@]}
    key3 key2 key1
    
    $ echo ${#array[@]}
    3
    
    $ set | grep ^array=
    array=([key3]="blue" [key2]="black" [key1]="red" )
    
    $ printf "%s\n" ${!array[@]}|grep -q ^key2$ && echo key2 exist || echo key2 not exist
    key2 exist
    
    $ printf "%s\n" ${!array[@]}|grep -q ^key5$ && echo key5 exist || echo key5 not exist
    key5 not exist
    

    You could do the job without the need of externals tools (no printf|grep as pure bash), and why not, build checkIfExist() as a new bash function:

    $ checkIfExist() {
        eval 'local keys=${!'$1'[@]}';
        eval "case '$2' in
            ${keys// /|}) return 0 ;;
            * ) return 1 ;;
          esac";
    }
    
    $ checkIfExist array key2 && echo exist || echo don\'t
    exist
    
    $ checkIfExist array key5 && echo exist || echo don\'t
    don't
    

    or even create a new getIfExist bash function that return the desired value and exit with false result-code if desired value not exist:

    $ getIfExist() {
        eval 'local keys=${!'$1'[@]}';
        eval "case '$2' in
            ${keys// /|}) echo \${$1[$2]};return 0 ;;
            * ) return 1 ;;
          esac";
    }
    
    $ getIfExist array key1
    red
    $ echo $?
    0
    
    $ # now with an empty defined value
    $ array["key4"]=""
    $ getIfExist array key4
    
    $ echo $?
    0
    $ getIfExist array key5
    $ echo $?
    1
    
    0 讨论(0)
  • 2020-12-02 07:54

    What about a -z test and the :- operator?

    For example, this script:

    #!/usr/bin/env bash
    
    set -e
    set -u
    
    declare -A sample
    
    sample["ABC"]=2
    sample["DEF"]=3
    
    if [[ ! -z "${sample['ABC']:-}" ]]; then
      echo "ABC is set"
    fi
    
    if [[ ! -z "${sample['DEF']:-}" ]]; then
      echo "DEF is set"
    fi
    
    if [[ ! -z "${sample['GHI']:-}" ]]; then
      echo "GHI is set"
    fi
    

    Prints:

    ABC is set
    DEF is set
    
    0 讨论(0)
提交回复
热议问题