117 votes

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

Utilisation :

set -o nounset
  1. Avoir un tableau indexé comme :

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

    Quel est le moyen le plus court de vérifier si l'élément 1 est défini ?
    J'utilise parfois ce qui suit :

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

    J'aimerais savoir s'il y a une préférence.

  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à fixé 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 ?

163voto

doubleDown Points 3245

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

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

En gros, ce que ${array[key]+abc} fait est

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

Références :

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

si le deux-points est omis, l'opérateur vérifie uniquement l'existence [de paramètre ]

  1. Cette réponse est en fait adaptée des réponses à cette question de l'OS : Comment dire si une chaîne de caractères n'est pas définie dans un shell bash script. ?

Une fonction d'enveloppement :

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

0 votes

J'ai résolu le problème de la manière suivante : if test "${myArray['key_or_index']+isset}" ; then echo "yes" ; else echo "no" ; fi ; Il me semble que c'est la manière la plus simple et qu'elle s'applique aux tableaux indexés et associatifs. Je vous remercie de votre attention et vous prie d'agréer, Madame, Monsieur, mes salutations distinguées.

1 votes

@doubleDown Comment utiliser [ ${array[key]+abc} ] dans une clause if pour ne faire quelque chose que si [ ${array[key]+abc} ] n'existe pas ?

1 votes

Cela ne fonctionne pas non plus lorsque vous demandez accidentellement un tableau énuméré en tant que tableau associatif.

62voto

Vineet Points 984

Desde coup d'homme les 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 ce dernier est défini par une valeur vide) et que foo[quux] ne l'est pas.

2 votes

Je l'ai raté d'un coup d'œil rapide ; remarquez que la syntaxe typique d'expansion de tableau n'est pas utilisée.

0 votes

Avec set -u pourquoi [[ -v "${foo[bar]}" ]] produit une erreur de variable non liée si bar n'existe pas dans le dictionnaire ? Cela fonctionne très bien sans l'option ${} J'ai juste l'habitude de l'utiliser par défaut pour tout.

3 votes

"${foo[bar]}" évalue d'abord la variable tableau, de sorte que la fonction [[ -v teste la présence d'une variable portant le nom de cette valeur

23voto

F. Hauri Points 5893

Nouvelle réponse

À partir de la version 4.2 de bash (et plus récents), il existe une nouvelle -v à l'option intégrée test commandement.

À partir de la version 4.3, ce test pouvait porter sur les éléments des tableaux.

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

Note : concernant commentaire de ssc J'ai simple Cité sur 'array[i]' en -v afin de satisfaire le test de shellcheck. erreur SC2208 . Cela ne semble pas vraiment nécessaire ici, car il n'y a pas de caractère glob dans array[i] de toute façon...

Ce travail avec tableaux associatifs de la même manière :

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

Avec une petite différence :
Dans les tableaux réguliers, les variables entre parenthèses ( [i] ) est un nombre entier, donc le symbole du dollar ( $ ) n'est pas nécessaire, mais pour un tableau associatif, comme clé est un mot, $ est nécessaire ( [$i] ) !

Ancienne réponse pour bash avant la V4.2

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

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 donnez pas de réponse)

Et pour les tableaux associatifs, 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 pourriez faire le travail sans avoir besoin d'outils externes (pas de printf|grep en tant que pure bash ), et pourquoi pas, construire checkIfExist() comme une 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 getIfExist Fonction bash qui retourne la valeur désirée et sort avec un code résultat faux si la valeur désiré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

0 votes

Ok pour les downvotes : Cette réponse a été postée avant la V4.2 de bash ! Réponse éditée !

0 votes

Ne fonctionne pas sur bash 4.2.46 . Fonctionne sur bash 4.4.12 .

0 votes

@Irfy Qu'est-ce qui ne fonctionne pas ? -v option de test ou getIfExist fonction ?

11voto

GuyPaddock Points 448

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

Par exemple, ce script :

#!/usr/bin/env bash

set -e
set -u

declare -A sample

sample["ABC"]=2
sample["DEF"]=3

if [[ -n "${sample['ABC']:-}" ]]; then
  echo "ABC is set"
fi

if [[ -n "${sample['DEF']:-}" ]]; then
  echo "DEF is set"
fi

if [[ -n "${sample['GHI']:-}" ]]; then
  echo "GHI is set"
fi

Imprimés :

ABC is set
DEF is set

0 votes

Excellente solution compacte qui répond comme prévu à une chaîne de caractères vide

0 votes

Un grand bravo pour cette solution qui fonctionne avec set -u dans bash 4.2. En ce moment, je travaille avec Oracle Database sur Red Hat 7, et bash 4.2 y est installé.

0 votes

C'est la réponse qui devrait être acceptée ! Elle a fonctionné pour moi (bash 4.2.46) alors que la réponse acceptée -v n'a pas fonctionné.

5voto

gdoubleod Points 194

Testé dans 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 votes

Cela échoue lorsque la valeur de la clé est une chaîne vide. Pour contourner le problème, vous pouvez utiliser la fonction + pour remplacer une valeur vide par un caractère générique, comme un trait de soulignement. Par exemple declare -A a[x]=;[[ ${a[x]} ]];echo $? empreintes 1 mais declare -A a[x]=;[[ ${a[x]+_} ]];echo $? empreintes 0 .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X