Bash array überprüfen?
Hallo
Wie kann ich in bash überprüfen, ob Arr1 mit einem von Arr2 übereinstimmt?
Beispiel:
Arr1="hallo"
Arr2=( "one" "two" "three" "hallo" "bye" "day" "10" )
if [[ " ${Arr2[*]} " =~ " $Arr1 " ]]; then
echo "irgendwas"
else
echo "irgendwas anderes"
fi
Dieser Code klappt nicht so gut wenn man viele Wörter in Arr2 gespeichert hat.
Ich kann jede Hilfe gebrauchen, danke.
2 Antworten
j=0
while [[ $j -le ${#Arr2[@]} ]]; do
[[ "${Arr1[0]}" == "${Arr2[$j]}" ]] && echo "found"
let j=j+1
done
Das ist natürlich eher Pseudo-Code und natürlich würde man die Schleife sofort verlassen, wenn etwas gefunden wurde.
Ja klar - ich habe ja nur einen Einzeiler gemacht.
j=0
while [[ $j -le ${#Arr2[@]} ]]; do
if [[ "${Arr1[0]}" == "${Arr2[$j]}" ]]; then
echo "found"
break
fi
let j=j+1
done
Das habe ich jetzt aber nicht weiter getestet.
wenn man viele Wörter in Arr2 gespeichert hat
Wie viel sind denn „viele“? Deine Version sieht zwar gruselig aus, ist aber deutlich schneller als alles, was mir an Alternativen einfällt. Bei 4 000 000 Werten messe ich:
Testumgebung: GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
Arr1 = 1001 # nicht in Arr2 enthalten
Arr2=( $(seq -1000001 3 11000000) ) # 4000001 Werte
Bemerkung: ${Arr2[*]/!($Arr1)} löscht jeden Eintrag != $Arr1. Übrig bleiben 4 Mio. leere Strings und ggf. der letzte Buchstabe eines exakten Treffers.
Mit time (built-in) gemessen:
- 10,3s: for w in ${Arr2[*]}; do if test $w = $Arr1; then echo Yes; break; fi done
- 2,9s: if test $(echo ${Arr2[*]/!($Arr1)})X != X; then echo Yes; fi
- 2,6s: for w in ${Arr2[*]/!($Arr1)}; do echo Yes; break; done
- 0,8s: if [[ " ${Arr2[*]} " =~ " $Arr1 " ]]; then echo Yes; fi
Alle Zeiten verhalten sich grob linear zur Länge von Arr2. Die Varianten mit for-Schleife werden marginal schneller, wenn der Eintrag früh gefunden wird.
Fazit: Deine Variante erschlägt 10 Millionen Einträge in ca. zwei Sekunden. Für ein Shellskript ist das gar nicht so nicht übel. Wenn Du mehr brauchst, musst Du wohl ein Python-Skript schreiben.
Die Bash kann auch assoziative Arrays. Das Anlegen dauert etwas länger, aber der Zugriff geht dann wirklich flott (nicht messbar):
declare -A Arr2
for key in $(seq -f "K%.f" -1000000 3 29000000); do Arr2+=($key $key); done
if test -n "${Arr2[$Arr1]}"; then echo YES; else echo No; fi
Gibt es auch eine Möglichkeit "if" zu verwenden?