Antworten:
In Bash 4 können Sie assoziative Arrays verwenden:
# set up array of constants
declare -A array
for constant in foo bar baz
do
array[$constant]=1
done
# test for existence
test1="bar"
test2="xyzzy"
if [[ ${array[$test1]} ]]; then echo "Exists"; fi # Exists
if [[ ${array[$test2]} ]]; then echo "Exists"; fi # doesn't
Um das Array zunächst einzurichten, können Sie auch direkte Zuweisungen vornehmen:
array[foo]=1
array[bar]=1
# etc.
oder so:
array=([foo]=1 [bar]=1 [baz]=1)
${array[$test1]}
ist einfach, hat aber ein Problem: Es funktioniert nicht, wenn Sie set -u
in Ihren Skripten verwenden (was empfohlen wird), da Sie "ungebundene Variable" erhalten würden.
Es ist eine alte Frage, aber ich denke , was die einfachste Lösung schien noch nicht ist: test ${array[key]+_}
. Beispiel:
declare -A xs=([a]=1 [b]="")
test ${xs[a]+_} && echo "a is set"
test ${xs[b]+_} && echo "b is set"
test ${xs[c]+_} && echo "c is set"
Ausgänge:
a is set
b is set
Um zu sehen, wie dies funktioniert, überprüfen Sie dies .
env
, um Unklarheiten in Aliasen, Progs und anderen Funktionen zu vermeiden, die möglicherweise den Namen "Test" angenommen haben. Wie oben env test ${xs[a]+_} && echo "a is set"
. Sie können diese Funktion auch mit doppelten Klammern erhalten, wobei derselbe Trick dann auf null prüft:[[ ! -z "${xs[b]+_}" ]] && echo "b is set"
[[ ${xs[b]+set} ]]
Es gibt eine Möglichkeit zu testen, ob ein Element eines assoziativen Arrays existiert (nicht gesetzt). Dies unterscheidet sich von leer:
isNotSet() {
if [[ ! ${!1} && ${!1-_} ]]
then
return 1
fi
}
Dann benutze es:
declare -A assoc
KEY="key"
isNotSet assoc[${KEY}]
if [ $? -ne 0 ]
then
echo "${KEY} is not set."
fi
if ! some_check then return 1
= some_check
. Also: isNotSet() { [[ ... ]] }
. Überprüfen Sie meine Lösung unten, Sie können es in einem einfachen Check tun.
Sie können feststellen, ob ein Eintrag vorhanden ist, indem Sie den Inhalt des Arrays an grep weiterleiten.
printf "%s\n" "${mydata[@]}" | grep "^${val}$"
Sie können auch den Index eines Eintrags mit grep -n abrufen, der die Zeilennummer einer Übereinstimmung zurückgibt (denken Sie daran, 1 zu subtrahieren, um einen auf Null basierenden Index zu erhalten). Dies ist mit Ausnahme sehr großer Arrays relativ schnell.
# given the following data
mydata=(a b c "hello world")
for val in a c hello "hello world"
do
# get line # of 1st matching entry
ix=$( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 )
if [[ -z $ix ]]
then
echo $val missing
else
# subtract 1. Bash arrays are zero-based, but grep -n returns 1 for 1st line, not 0
echo $val found at $(( ix-1 ))
fi
done
a found at 0
c found at 2
hello missing
hello world found at 3
Erläuterung:
$( ... )
entspricht der Verwendung von Backticks zum Erfassen der Ausgabe eines Befehls in eine Variable printf
gibt mydata ein Element pro Zeile aus @
anstatt *.
dies vermeidet Splitting „Hallo Welt“ in 2 Zeilen)grep
Sucht nach genauem String: ^
und $
stimmt mit Zeilenanfang und Zeilenende übereingrep -n
Gibt Zeile # in Form von 4 zurück: Hallo Welt grep -m 1
findet nur die erste Übereinstimmungcut
extrahiert nur die Zeilennummer Sie können die Subtraktion natürlich in den Befehl einklappen. Aber dann teste auf -1, ob etwas fehlt:
ix=$(( $( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 ) - 1 ))
if [[ $ix == -1 ]]; then echo missing; else ... fi
$(( ... ))
führt eine Ganzzahl-Arithmetik durchIch denke nicht, dass Sie es ohne Schleife richtig machen können, es sei denn, Sie haben sehr begrenzte Daten im Array.
Hier ist eine einfache Variante, dies würde richtig sagen, dass "Super User"
es in dem Array existiert. Aber es würde auch sagen, dass "uper Use"
das in der Reihe ist.
MyArray=('Super User' 'Stack Overflow' 'Server Fault' 'Jeff' );
FINDME="Super User"
FOUND=`echo ${MyArray[*]} | grep "$FINDME"`
if [ "${FOUND}" != "" ]; then
echo Array contains: $FINDME
else
echo $FINDME not found
fi
#
# If you where to add anchors < and > to the data it could work
# This would find "Super User" but not "uper Use"
#
MyArray2=('<Super User>' '<Stack Overflow>' '<Server Fault>' '<Jeff>' );
FOUND=`echo ${MyArray2[*]} | grep "<$FINDME>"`
if [ "${FOUND}" != "" ]; then
echo Array contains: $FINDME
else
echo $FINDME not found
fi
Das Problem ist, dass es keine einfache Möglichkeit gibt, die Anker (die ich mir vorstellen kann) hinzuzufügen, außer das Array zu durchlaufen. Es sei denn, Sie können sie hinzufügen, bevor Sie sie in das Array einfügen ...
grep "\b$FINDME\b"
). "(^| )$FINDME(\$| )"
Könnte wahrscheinlich mit nicht-alphanumerischen Konstanten arbeiten, die keine Leerzeichen haben, mit (oder so ähnlichem ... Ich habe nie erfahren können, welche Variante von Regexp grep verwendet.)
#!/bin/bash
function in_array {
ARRAY=$2
for e in ${ARRAY[*]}
do
if [[ "$e" == "$1" ]]
then
return 0
fi
done
return 1
}
my_array=(Drupal Wordpress Joomla)
if in_array "Drupal" "${my_array[*]}"
then
echo "Found"
else
echo "Not found"
fi
in_array
. Cheers
${ARRAY[@]}
verwendet werden.