web-dev-qa-db-fra.com

Le moyen le plus simple de rechercher un index ou une clé dans un tableau?

En utilisant:

set -o nounset

1) Avoir un tableau indexé comme:

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

Quel est le moyen le plus rapide de vérifier si l'élément 1 est défini?
J'utilise parfois les éléments suivants:

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

J'aimerais savoir s'il y en a un préféré.

2) Comment traiter les index non consécutifs?

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

Comment vérifier rapidement que '51' est déjà défini, par exemple?

3) Comment traiter les tableaux associatifs?

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

Comment vérifier rapidement que 'key2' est déjà utilisé par exemple?

Merci

ÉDITÉ
La manière la plus simple me semble:

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

Cela fonctionne à la fois pour les tableaux indexés et associatifs. Aucune erreur affichée avec set -o nounset.
Merci à doubleDown pour le heads-up.

72
Luca Borrione

Pour vérifier si l'élément est défini (s'applique à la fois aux tableaux indexés et associatifs)

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

Fondamentalement ce que ${array[key]+abc} fait est

  • si array[key] est défini, retourne abc
  • si array[key] n'est pas défini, ne renvoie rien

  1. Voir Expansion des paramètres dans le manuel de Bash et la petite note

    si les deux points sont omis, l'opérateur ne vérifie que l'existence [de paramètre ]

  2. Cette réponse est en réalité adaptée des réponses pour ceci SO question: Comment savoir si une chaîne n'est pas définie dans un script shell bash) ?


Une fonction wrapper:

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

Par exemple

if ! exists key in array; then echo "No such array element"; fi 
107
doubleDown

De man bash , expressions conditionnelles:

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

exemple:

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

Cela montrera que foo [bar] et foo [baz] sont tous deux définis (même si cette dernière est définie sur une valeur vide) et que foo [quux] ne l’est pas.

21
Vineet

Malheureusement, bash ne donne aucun moyen de faire la différence entre vide et variable indéfinie .

Mais il y a des moyens:

$ 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

(ne pas répondre)

Et pour un tableau associatif, vous pouvez utiliser la même chose:

$ 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

Vous pouvez faire le travail sans avoir besoin d’outils externes (pas printf | grep as pure bash ), et pourquoi pas, build checkIfExist ( ) en tant que nouvelle fonction bash:

$ 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

ou même créer une nouvelle fonction getIfExist bash qui renvoie la valeur souhaitée et quitte avec un code de résultat faux si la valeur souhaitée n'existe pas:

$ 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
6
F. Hauri

testé en version 4.3.39 (1)

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
gdoubleod

J'ai écrit une fonction pour vérifier si une clé existe dans un tableau dans 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
}

Exemple

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

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

Testé avec GNU bash, version 4.1.5 (1) -release (i486-pc-linux-gnu)

1
Lucas Stad

C'est le moyen le plus simple que j'ai trouvé pour les scripts.

<search> est la chaîne que vous voulez trouver, ASSOC_ARRAY le nom de la variable contenant votre tableau associatif.

Dépend de ce que vous voulez réaliser:

clé existe :

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

la clé n'existe pas :

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

valeur existe :

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

la valeur existe pas :

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

Qu'en est-il d'un -z test et le :- opérateur?

Par exemple, ce 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

Impressions:

ABC is set
DEF is set
0
GuyPaddock