Wie kann man in Bash am einfachsten testen, ob ein Array einen bestimmten Wert enthält?
Antworten
Zu viele Anzeigen?Normalerweise verwende ich nur:
inarray=$(echo ${haystack[@]} | grep -o "needle" | wc -w)
Ein Wert ungleich Null bedeutet, dass eine Übereinstimmung gefunden wurde.
... um das Problem zu lösen, dass es mit needle1 und needle2 nicht funktioniert, wenn Sie nur eine exakte Übereinstimmung wollen, nicht mehr und nicht weniger, fügen Sie einfach ein w
Kennzeichen nach dem -o
für eine Übereinstimmung mit einem ganzen Wort:
inarray=$(echo ${haystack[@]} | grep -ow "needle" | wc -w)
Wenn Sie Leistung benötigen, möchten Sie nicht bei jeder Suche eine Schleife über Ihr gesamtes Array laufen lassen.
In diesem Fall können Sie ein assoziatives Array (Hashtabelle oder Wörterbuch) erstellen, das einen Index dieses Arrays darstellt. Das heißt, jedes Array-Element wird auf seinen Index im Array abgebildet:
make_index () {
local index_name=$1
shift
local -a value_array=("$@")
local i
# -A means associative array, -g means create a global variable:
declare -g -A ${index_name}
for i in "${!value_array[@]}"; do
eval ${index_name}["${value_array[$i]}"]=$i
done
}
Dann können Sie es so verwenden:
myarray=('a a' 'b b' 'c c')
make_index myarray_index "${myarray[@]}"
Und testen Sie die Mitgliedschaft wie folgt:
member="b b"
# the "|| echo NOT FOUND" below is needed if you're using "set -e"
test "${myarray_index[$member]}" && echo FOUND || echo NOT FOUND
Oder auch:
if [ "${myarray_index[$member]}" ]; then
echo FOUND
fi
Beachten Sie, dass diese Lösung auch dann das Richtige tut, wenn der getestete Wert oder die Array-Werte Leerzeichen enthalten.
Als Bonus erhalten Sie mit auch den Index des Wertes innerhalb des Arrays:
echo "<< ${myarray_index[$member]} >> is the index of $member"
Ein weiterer One-Liner ohne Funktion:
(for e in "${array[@]}"; do [[ "$e" == "searched_item" ]] && exit 0; done) && echo "found" || echo "not found"
Danke @Qwerty für den Hinweis auf die Leerzeichen!
entsprechende Funktion:
find_in_array() {
local word=$1
shift
for e in "$@"; do [[ "$e" == "$word" ]] && return 0; done
return 1
}
Beispiel:
some_words=( these are some words )
find_in_array word "${some_words[@]}" || echo "expected missing! since words != word"
Wie prüft man, ob ein Bash-Array einen Wert enthält?
Falsch positive Übereinstimmung
array=(a1 b1 c1 d1 ee)
[[ ${array[*]} =~ 'a' ]] && echo 'yes' || echo 'no'
# output:
yes
[[ ${array[*]} =~ 'a1' ]] && echo 'yes' || echo 'no'
# output:
yes
[[ ${array[*]} =~ 'e' ]] && echo 'yes' || echo 'no'
# output:
yes
[[ ${array[*]} =~ 'ee' ]] && echo 'yes' || echo 'no'
# output:
yes
Genaue Übereinstimmung
Um nach einer exakten Übereinstimmung zu suchen, muss Ihr Regex-Muster zusätzliche Leerzeichen vor und nach dem Wert hinzufügen, wie (^|[[:space:]])"VALUE"($|[[:space:]])
# Exact match
array=(aa1 bc1 ac1 ed1 aee)
if [[ ${array[*]} =~ (^|[[:space:]])"a"($|[[:space:]]) ]]; then
echo "Yes";
else
echo "No";
fi
# output:
No
if [[ ${array[*]} =~ (^|[[:space:]])"ac1"($|[[:space:]]) ]]; then
echo "Yes";
else
echo "No";
fi
# output:
Yes
find="ac1"
if [[ ${array[*]} =~ (^|[[:space:]])"$find"($|[[:space:]]) ]]; then
echo "Yes";
else
echo "No";
fi
# output:
Yes
Weitere Beispiele für die Verwendung finden Sie unter aquí
Wenn Sie einen schnellen und schmutzigen Test durchführen wollen, um zu sehen, ob es sich lohnt, über das gesamte Array zu iterieren, um eine genaue Übereinstimmung zu erhalten, kann Bash Arrays wie Skalare behandeln. Testen Sie auf eine Übereinstimmung im Skalar, wenn es keine gibt, können Sie die Schleife überspringen und Zeit sparen. Offensichtlich kann es zu falsch positiven Ergebnissen kommen.
array=(word "two words" words)
if [[ ${array[@]} =~ words ]]
then
echo "Checking"
for element in "${array[@]}"
do
if [[ $element == "words" ]]
then
echo "Match"
fi
done
fi
Dies führt zur Ausgabe von "Checking" und "Match". Mit array=(word "two words" something)
wird nur "Prüfen" ausgegeben. Mit array=(word "two widgets" something)
gibt es keine Ausgabe.