Risposte:
In Bash 4, puoi usare array associativi:
# 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
Per configurare l'array inizialmente è possibile anche eseguire assegnazioni dirette:
array[foo]=1
array[bar]=1
# etc.
o in questo modo:
array=([foo]=1 [bar]=1 [baz]=1)
${array[$test1]}
è semplice ma ha un problema: non funzionerà se lo usi set -u
nei tuoi script (che è consigliato), dato che otterrai "variabile non associata".
E 'una vecchia questione, ma credo che ciò che è la soluzione più semplice non è ancora apparso: test ${array[key]+_}
. Esempio:
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"
Uscite:
a is set
b is set
Per vedere come funziona controlla questo .
env
per evitare ambiguità in alias, prog e altre funzioni che potrebbero aver adottato il nome "test". Come sopra env test ${xs[a]+_} && echo "a is set"
. Puoi anche ottenere questa funzionalità usando le parentesi doppie, lo stesso trucco quindi controllando null:[[ ! -z "${xs[b]+_}" ]] && echo "b is set"
[[ ${xs[b]+set} ]]
C'è un modo per testare se esiste un elemento di un array associativo (non impostato), questo è diverso da vuoto:
isNotSet() {
if [[ ! ${!1} && ${!1-_} ]]
then
return 1
fi
}
Quindi usalo:
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
. Quindi: isNotSet() { [[ ... ]] }
. Controlla la mia soluzione di seguito, puoi farlo con un semplice controllo.
Puoi vedere se è presente una voce eseguendo il piping del contenuto dell'array su grep.
printf "%s\n" "${mydata[@]}" | grep "^${val}$"
È anche possibile ottenere l'indice di una voce con grep -n, che restituisce il numero di riga di una corrispondenza (ricordarsi di sottrarre 1 per ottenere un indice in base zero) Questo sarà ragionevolmente veloce, tranne che per array molto grandi.
# 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
spiegazione:
$( ... )
equivale a utilizzare i backtick per acquisire l'output di un comando in una variabile printf
genera mydata un elemento per riga @
invece *.
evita di dividere "ciao mondo" in 2 righe)grep
cerca la stringa esatta: ^
e $
corrisponde all'inizio e alla fine della rigagrep -n
ritorna riga #, in forma di 4: ciao mondo grep -m 1
trova solo la prima partitacut
estrae solo il numero di riga Ovviamente puoi piegare la sottrazione nel comando. Ma quindi prova -1 per mancare:
ix=$(( $( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 ) - 1 ))
if [[ $ix == -1 ]]; then echo missing; else ... fi
$(( ... ))
fa l'aritmetica interaNon penso che tu possa farlo correttamente senza loop a meno che tu non abbia dati molto limitati nell'array.
Ecco una semplice variante, questo direbbe correttamente che "Super User"
esiste nella matrice. Ma direbbe anche che "uper Use"
è nella matrice.
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
Il problema è che non esiste un modo semplice per aggiungere gli ancoraggi (a cui riesco a pensare) oltre a fare il loop nell'array. A meno che non sia possibile aggiungerli prima di inserirli nell'array ...
grep "\b$FINDME\b"
). Probabilmente potrebbe funzionare con costanti non alfanumeriche che non hanno spazi, con "(^| )$FINDME(\$| )"
(o qualcosa del genere ... Non sono mai stato in grado di apprendere quale sapore utilizza regexp grep.)
#!/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
. Saluti
${ARRAY[@]}
dovrebbe essere usato.