Vérifier si un élément est présent dans un tableau Bash

Je me demandais s’il existe un moyen efficace de vérifier si un élément est présent dans un tableau dans Bash? Je cherche quelque chose de similaire à ce que je peux faire en Python, comme:

arr = ['a','b','c','d'] if 'd' in arr: do your thing else: do something 

J’ai vu des solutions utilisant un tableau associatif pour bash pour Bash 4+, mais je me demande s’il existe une autre solution.

S’il vous plaît comprendre que je sais que la solution sortingviale est d’itérer dans le tableau, mais je ne le veux pas.

Vous pourriez faire:

 if [[ " ${arr[*]} " == *" d "* ]]; then echo "arr contains d" fi 

Cela donnera des faux positifs, par exemple si vous recherchez “ab” – cette sous-chaîne est dans la chaîne jointe mais pas en tant qu’élément de tableau. Ce dilemme se produira pour n’importe quel délimiteur que vous choisissez.

Le moyen le plus sûr est de parcourir le tableau jusqu’à ce que vous trouviez l’élément:

 array_contains () { local seeking=$1; shift local in=1 for element; do if [[ $element == $seeking ]]; then in=0 break fi done return $in } arr=(abc "de" fg) array_contains "ab" "${arr[@]}" && echo yes || echo no # no array_contains "de" "${arr[@]}" && echo yes || echo no # yes 

Voici une version “plus propre” où vous passez simplement le nom du tableau, pas tous ses éléments

 array_contains2 () { local array="$1[@]" local seeking=$2 local in=1 for element in "${!array}"; do if [[ $element == $seeking ]]; then in=0 break fi done return $in } array_contains2 arr "ab" && echo yes || echo no # no array_contains2 arr "de" && echo yes || echo no # yes 

Mises en garde évidentes de côté, si votre tableau était en fait comme celui ci-dessus, vous pourriez faire

 if [[ ${arr[*]} =~ d ]] then do your thing else do something fi 

Si les éléments du tableau ne contiennent pas d’espaces, une autre solution (peut-être plus lisible) serait:

 if echo ${arr[@]} | grep -q -w "d"; then echo "is in array" else echo "is not in array" fi 

1) Initialiser le tableau arr et append des éléments

2) définir la variable pour rechercher SEARCH_STRING

3) vérifier si votre tableau contient des éléments

 arr=() arr+=('a') arr+=('b') arr+=('c') SEARCH_STRING='b' if [[ " ${arr[*]} " == *"$SEARCH_STRING"* ]]; then echo "YES, your arr contains $SEARCH_STRING" else echo "NO, your arr does not contain $SEARCH_STRING" fi 

Voici un autre moyen qui pourrait être plus rapide, en termes de temps de calcul, que d’itérer. Pas certain. L’idée est de convertir le tableau en chaîne, de le tronquer et d’obtenir la taille du nouveau tableau.

Par exemple, pour trouver l’index de ‘d’:

 arr=(abcd) temp=`echo ${arr[@]}` temp=( ${temp%%d*} ) index=${#temp[@]} 

Vous pourriez transformer ceci en une fonction comme:

 get-index() { Item=$1 Array="$2[@]" ArgArray=( ${!Array} ) NewArray=( ${!Array%%${Item}*} ) Index=${#NewArray[@]} [[ ${#ArgArray[@]} == ${#NewArray[@]} ]] && echo -1 || echo $Index } 

Vous pouvez alors appeler:

 get-index d arr 

et cela reviendrait 3, qui serait assignable avec:

 index=`get-index d arr` 

FWIW, voici ce que j’ai utilisé:

 expr "${arr[*]}" : ".*\<$item\>" 

Cela fonctionne là où il n’y a aucun délimiteur dans aucun des éléments du tableau ou dans la cible de recherche. Je n’ai pas eu besoin de résoudre le cas général pour mon application.

 array=("word" "two words") # let's look for "two words" 

en utilisant grep et printf :

 (printf '%s\n' "${array[@]}" | grep -x -q "two words") &&  

en utilisant for :

 (for e in "${array[@]}"; do [[ "$e" == "two words" ]] && exit 0; done; exit 1) &&  

Pour les résultats not_found add || ||