Ich habe mich gefragt, ob es eine effiziente Möglichkeit gibt, zu überprüfen, ob ein Element in einem Array in Bash vorhanden ist. Ich suche etwas Ähnliches wie das, was ich in Python tun kann, wie:
arr = ['a','b','c','d']
if 'd' in arr:
do your thing
else:
do something
Ich habe Lösungen gesehen, die assoziatives Array für Bash für Bash 4+ verwenden, aber ich frage mich, ob es da draußen eine andere Lösung gibt.
Bitte haben Sie Verständnis dafür, dass ich weiß, dass die triviale Lösung darin besteht, im Array zu iterieren, aber das möchte ich nicht.
bash
, mit einem einfachen Array das zu tun, was Sie wollen.Antworten:
Du könntest es tun:
if [[ " ${arr[*]} " == *" d "* ]]; then echo "arr contains d" fi
Dies führt beispielsweise zu falsch positiven Ergebnissen, wenn Sie nach "a b" suchen - dieser Teilstring befindet sich in der verknüpften Zeichenfolge, jedoch nicht als Array-Element. Dieses Dilemma tritt für jedes von Ihnen gewählte Trennzeichen auf.
Am sichersten ist es, das Array zu durchlaufen, bis Sie das Element finden:
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
Hier ist eine "sauberere" Version, bei der Sie nur den Array-Namen und nicht alle Elemente übergeben
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
Bei assoziativen Arrays gibt es eine sehr übersichtliche Methode, um zu testen, ob das Array einen bestimmten Schlüssel enthält : den
-v
Operator$ declare -A arr=( [foo]=bar [baz]=qux ) $ [[ -v arr[foo] ]] && echo yes || echo no yes $ [[ -v arr[bar] ]] && echo yes || echo no no
Siehe 6.4 Bedingte Bash-Ausdrücke im Handbuch.
quelle
$seeking
damit es nicht als Muster betrachtet wird.Abgesehen von offensichtlichen Einschränkungen könnten Sie dies tun, wenn Ihr Array tatsächlich dem oben genannten entspricht
if [[ ${arr[*]} =~ d ]] then do your thing else do something fi
quelle
d
Wird aber auch passenxdy
.if [[ ${arr[*]} =~ $(echo '\<d\>') ]]
( Quelle )1) Array initialisieren
arr
und fügen Sie Elemente hinzu2) Setzen Sie die Variable, nach der gesucht werden soll
SEARCH_STRING
3) Überprüfen Sie, ob Ihr Array ein Element enthält
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
quelle
BASH_ARGV
zu testen, ob ein bestimmtes Wort als Argument angegeben wurde, das ein anderes einmaliges Setup erfordert, ohne dass ich etwas tun musste,argparse
was für diesen Fall übertrieben ist.Wenn Array-Elemente keine Leerzeichen enthalten, wäre eine andere (möglicherweise besser lesbare) Lösung:
if echo ${arr[@]} | grep -q -w "d"; then echo "is in array" else echo "is not in array" fi
quelle
--
, um das Ende der Parameter zu signalisieren, und negative Zahlen werden nicht als Parameter für greparray=("word" "two words") # let's look for "two words"
mit
grep
undprintf
:(printf '%s\n' "${array[@]}" | grep -x -q "two words") && <run_your_if_found_command_here>
mit
for
:(for e in "${array[@]}"; do [[ "$e" == "two words" ]] && exit 0; done; exit 1) && <run_your_if_found_command_here>
Für not_found Ergebnisse hinzufügen
|| <run_your_if_notfound_command_here>
quelle
grep -x...
macht es am einfachsten zu bedienen.Da bash nicht über einen eingebauten in Wert
in
Array Betreiber und dem=~
Betreiber oder der[[ "${array[@]" == *"${item}"* ]]
keep Notation verwirrend mich, ich in der Regel kombinierengrep
mit einer hier string:colors=('black' 'blue' 'light green') if grep -q 'black' <<< "${colors[@]}" then echo 'match' fi
Beachten Sie jedoch, dass dies das gleiche Problem mit Fehlalarmen aufweist wie viele andere Antworten, die auftreten, wenn das zu suchende Element vollständig enthalten ist, aber nicht einem anderen Element entspricht:
if grep -q 'green' <<< "${colors[@]}" then echo 'should not match, but does' fi
Wenn dies ein Problem für Ihren Anwendungsfall ist, werden Sie wahrscheinlich nicht darum herumkommen, das Array zu durchlaufen:
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
quelle
-x
zu grep, um der gesamten Zeile zu entsprechen.Hier ist eine andere Möglichkeit, die in Bezug auf die Rechenzeit möglicherweise schneller ist als das Iterieren. Nicht sicher. Die Idee ist, das Array in eine Zeichenfolge zu konvertieren, es abzuschneiden und die Größe des neuen Arrays zu ermitteln.
So finden Sie beispielsweise den Index von 'd':
arr=(a b c d) temp=`echo ${arr[@]}` temp=( ${temp%%d*} ) index=${#temp[@]}
Sie könnten daraus eine Funktion machen wie:
get-index() { Item=$1 Array="$2[@]" ArgArray=( ${!Array} ) NewArray=( ${!Array%%${Item}*} ) Index=${#NewArray[@]} [[ ${#ArgArray[@]} == ${#NewArray[@]} ]] && echo -1 || echo $Index }
Sie könnten dann anrufen:
und es würde 3 zurückgeben, was zuweisbar wäre mit:
quelle
FWIW, hier ist was ich verwendet habe:
expr "${arr[*]}" : ".*\<$item\>"
Dies funktioniert, wenn in keinem der Array-Elemente oder im Suchziel Trennzeichen vorhanden sind. Ich musste den allgemeinen Fall für meine Bewerbung nicht lösen.
quelle