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

2019-01-16 07:21发布

Using:

set -o nounset

1) Having an indexed array like:

myArray=( "red" "black" "blue" )

Which is the shortest way to check if element 1 is set?
I sometimes use the following:

test "${#myArray[@]}" -gt "1" && echo "1 exists" || echo "1 doesn't exist"

I would like to know if there's a preferred one.

2) How to deal with non-consecutive indexes?

myArray=()
myArray[12]="red"
myArray[51]="black"
myArray[129]="blue"

How to quick check that '51' is already set for example?

3) How to deal with associative arrays?

declare -A myArray
myArray["key1"]="red"
myArray["key2"]="black"
myArray["key3"]="blue"

How to quick check that 'key2' is already used for example?

Thanks

EDITED
The simplest way seems to me:

if test "${myArray['key_or_index']+isset}"
    then
        echo "yes"
    else
        echo "no"
fi;

This works for both indexed and associative arrays. No errors shown with set -o nounset.
Thanks to doubleDown for the headup.

6条回答
Deceive 欺骗
2楼-- · 2019-01-16 07:33

I wrote a function to check if a key exists in an array in Bash:

# Check if array key exists
# Usage: array_key_exists $array_name $key
# Returns: 0 = key exists, 1 = key does NOT exist
function array_key_exists() {
    local _array_name="$1"
    local _key="$2"
    local _cmd='echo ${!'$_array_name'[@]}'
    local _array_keys=($(eval $_cmd))
    local _key_exists=$(echo " ${_array_keys[@]} " | grep " $_key " &>/dev/null; echo $?)
    [[ "$_key_exists" = "0" ]] && return 0 || return 1
}

Example

declare -A my_array
my_array['foo']="bar"

if [[ "$(array_key_exists 'my_array' 'foo'; echo $?)" = "0" ]]; then
    echo "OK"
else
    echo "ERROR"
fi

Tested with GNU bash, version 4.1.5(1)-release (i486-pc-linux-gnu)

查看更多
你好瞎i
3楼-- · 2019-01-16 07:34

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 
查看更多
在下西门庆
4楼-- · 2019-01-16 07:44

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
查看更多
孤傲高冷的网名
5楼-- · 2019-01-16 07:46

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
查看更多
Root(大扎)
6楼-- · 2019-01-16 07:48

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
查看更多
Lonely孤独者°
7楼-- · 2019-01-16 07:49

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.

查看更多
登录 后发表回答