Wie kann man in Bash am einfachsten testen, ob ein Array einen bestimmten Wert enthält?
Antworten
Zu viele Anzeigen?Dieser Ansatz hat den Vorteil, dass keine Schleife über alle Elemente gezogen werden muss (zumindest nicht explizit). Aber da array_to_string_internal()
en array.c Schleift immer noch über Array-Elemente und verkettet sie zu einer Zeichenkette. Es ist wahrscheinlich nicht effizienter als die vorgeschlagenen Schleifenlösungen, aber es ist besser lesbar.
if [[ " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array contains value
fi
if [[ ! " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array doesn't contain value
fi
Beachten Sie, dass es in Fällen, in denen der gesuchte Wert eines der Wörter in einem Array-Element mit Leerzeichen ist, zu falsch positiven Ergebnissen führen kann. Zum Beispiel
array=("Jack Brown")
value="Jack"
Der Regex sieht "Jack" als im Array enthalten an, obwohl er es nicht ist. Sie müssen also Folgendes ändern IFS
und die Trennzeichen in Ihrer Regex, wenn Sie diese Lösung trotzdem verwenden wollen, etwa so
IFS="|"
array=("Jack Brown${IFS}Jack Smith")
value="Jack"
if [[ "${IFS}${array[*]}${IFS}" =~ "${IFS}${value}${IFS}" ]]; then
echo "true"
else
echo "false"
fi
unset IFS # or set back to original IFS if previously set
Dies führt zur Ausgabe von "false".
Natürlich kann dies auch als Testanweisung verwendet werden, so dass sie in einem Einzeiler ausgedrückt werden kann
[[ " ${array[*]} " =~ " ${value} " ]] && echo "true" || echo "false"
Nachstehend finden Sie eine kleine Funktion, mit der Sie dies erreichen können. Der Suchstring ist das erste Argument und der Rest sind die Array-Elemente:
set +e #otherwise the script will exit on error
containsElement () {
local e match="$1"
shift
for e; do [[ "$e" == "$match" ]] && return 0; done
return 1
}
Ein Testlauf dieser Funktion könnte folgendermaßen aussehen:
$ array=("something to search for" "a string" "test2000")
$ containsElement "a string" "${array[@]}"
$ echo $?
0
$ containsElement "blaha" "${array[@]}"
$ echo $?
1
Einzeilige Lösung
printf '%s\0' "${myarray[@]}" | grep -F -x -z -- 'myvalue'
Erläuterung
Le site printf
Anweisung gibt jedes Element des Arrays aus, begrenzt durch Nullzeichen.
Le site grep
Anweisung verwendet die folgenden Flags, um ein Element zu finden, das Folgendes enthält まさに die Zeichenkette, die als myvalue
(nicht mehr und nicht weniger):
-z
/--null-data
- Die Zeilen werden mit einem Null-Byte anstelle eines Zeilenumbruchs abgeschlossen.-F
/--fixed-strings
- Interpretieren Sie PATTERNS als feste Zeichenketten, nicht als reguläre Ausdrücke.-x
/--line-regexp
- Wählen Sie nur die Treffer aus, die genau mit der gesamten Zeile übereinstimmen.--
- markiert das Ende der Befehlszeilenoptionen, so dass Grep den Prozess "myvalue
" als Nicht-Options-Argument, auch wenn es mit einem Bindestrich beginnt
Warum verwenden wir ein Null-Byte \0
anstelle eines Zeilenumbruchs \n
? Ihr Array kann tatsächlich Zeilenumbrüche innerhalb seiner Elemente enthalten. (Wenn Sie wissen, dass das nicht der Fall ist, können Sie das -z
grep-Option und Substitut %s\n
als Ihr erstes printf-Argument).
Verwendung
Um dies zu verdeutlichen if ... then
Erklärung:
if printf '%s\0' "${myarray[@]}" | grep -Fxqz -- 'myvalue'; then
# ...
fi
Ich habe eine -q
Flagge zum grep
Ausdruck, so dass er keine Übereinstimmungen ausgibt, sondern nur die Existenz einer Übereinstimmung als "wahr" behandelt.
Update : Danke, presto8, für den Hinweis auf die --line-regexp
Flagge. Danke, Tino, für den Hinweis auf den Fall, dass Zeilenumbrüche innerhalb von Array-Elementen vorkommen können.
- See previous answers
- Weitere Antworten anzeigen