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.
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
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
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
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
array=("Word" "two words") # let's look for "two words"
grep
et printf
:(printf '%s\n' "${array[@]}" | grep -x -q "two words") && <run_your_if_found_command_here>
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>
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`
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
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.