web-dev-qa-db-fra.com

Vérifier si un élément est présent dans un tableau de 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 déjà vu des solutions utilisant le tableau associatif pour bash pour Bash 4+, mais je me demande s'il existe une autre solution.

S'il vous plaît, comprenez que je sais que la solution triviale consiste à itérer dans le tableau, mais je ne le souhaite pas.

58
QuantumLicht

Vous pourriez faire:

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

Cela donnera des faux positifs par exemple si vous recherchez "a b" - cette sous-chaîne est dans la chaîne jointe mais pas en tant qu'élément de tableau. Ce dilemme se produira quel que soit le délimiteur que vous choisissez.

Le moyen le plus sûr est de passer en boucle sur 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=(a b c "d e" f g)
array_contains "a b" "${arr[@]}" && echo yes || echo no    # no
array_contains "d e" "${arr[@]}" && echo yes || echo no    # yes

Voici une version "plus propre" où vous venez de passer 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 "a b"  && echo yes || echo no    # no
array_contains2 arr "d e"  && echo yes || echo no    # yes
84
glenn jackman

Mises en garde évidentes de côté, si votre tableau était en réalité le même que celui ci-dessus, vous pourriez le faire.

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

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

2) définir la variable pour rechercher SEARCH_STRING

3) vérifiez si votre tableau contient un élément

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
14
Marcin Wasiluk

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
11
jesjimher
array=("Word" "two words") # let's look for "two words"

en utilisant grep et printf:

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

en utilisant for:

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

Pour les résultats not_found, ajoutez || <run_your_if_notfound_command_here>

2
Qwerty

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=(a b c d)    
temp=`echo ${arr[@]}`
temp=( ${temp%%d*} )
index=${#temp[@]}

Vous pourriez en faire 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 ferait écho en arrière 3, ce qui serait assignable avec:

index=`get-index d arr`
2
Jasonovich

Comme bash n'a pas intégré valeurin tableau et l'opérateur =~ Ou le [[ "${array[@]" == *"${item}"* ]] Continue à me dérouter, je combine habituellement grep avec une chaîne ici:

colors=('black' 'blue' 'light green')
if grep -q 'black' <<< "${colors[@]}"
then
    echo 'match'
fi

Méfiez-vous Toutefois, cela pose le même problème de faux positifs que beaucoup d'autres réponses qui se produisent lorsque l'élément à rechercher est entièrement contenu, mais n'est pas égal à un autre élément:

if grep -q 'green' <<< "${colors[@]}"
then
    echo 'should not match, but does'
fi

Si cela pose un problème pour votre cas d'utilisation, vous n'allez probablement pas contourner le tableau:

for color in "${colors[@]}"
do
    if [ "${color}" = 'green' ]
    then
        echo "should not match and won't"
        break
    fi
done

for color in "${colors[@]}"
do
    if [ "${color}" = 'light green' ]
    then
        echo 'match'
        break
    fi
done
2
ssc

FWIW, voici ce que j'ai utilisé:

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

Cela fonctionne lorsqu'il n'y a pas de délimiteur dans les éléments du tableau ou dans la cible de recherche. Je n'avais pas besoin de résoudre le cas général de ma candidature.

0
Edward Falk