Matrici associative negli script di shell


11

Ho visto un trucco per implementare array associativi in ​​uno script di shell. Ad esempio, print array["apples"]potrebbe essere scritto come echo \$array$keydove chiave = mele.

Tuttavia, non è stato menzionato il modo in cui generare le chiavi per iterare sull'array. L'unico modo in cui mi è venuto in mente è stato quello di archiviare le chiavi in ​​una variabile delimitata da spazi in modo da poter utilizzare un for-loop per iterare sull'array.

Quindi, c'è un altro modo per memorizzare le chiavi per un uso successivo?


5
Se stai cercando di usare array associativi in ​​uno script di shell, potrebbe essere possibile che il tuo progetto sia troppo complesso per uno script di shell :)
Martin von Wittich,

@MartinvonWittich perché? Ho uno script di shell che esegue uno script SQL su uno dei 3 possibili schemi DB. Lo schema richiesto è incluso nel nome file con un'abbreviazione. Ho bisogno di una mappatura tra questa abbreviazione e il vero nome dello schema. Quale modo migliore di un array associativo, considerando i nomi degli schemi reali (non l'abbreviazione) può differire tra ambienti, quindi una variabile di array (i cui valori possono essere impostati solo una volta) è perfetta
Slav

2
@Slav Non sto discutendo contro array associativi, ma solo contro script shell dove è necessaria tale complessità. Ma questa è solo la mia preferenza personale; Mi capita spesso di iniziare a scrivere uno script di shell e poi di riscriverlo immediatamente in Perl quando mi rendo conto di superare una certa soglia di complessità.
Martin von Wittich,

Risposte:


20

Conchiglie con array associativi

Alcune shell moderne forniscono array associativi: ksh93, bash ≥4, zsh. In ksh93 e bash, se aè un array associativo, allora "${!a[@]}"è l'array delle sue chiavi:

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

In zsh, quella sintassi funziona solo in modalità di emulazione ksh. Altrimenti devi usare la sintassi nativa di zsh:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}funziona anche se anon ha una chiave vuota.

In zsh, puoi anche keseguire il loop su eys e values ​​contemporaneamente:

for k v ("${(@kv)a}") echo "$k -> $v"

Conchiglie senza array associativi

Emulare array associativi in ​​shell che non li hanno è molto più lavoro. Se hai bisogno di array associativi, è probabilmente il momento di introdurre uno strumento più grande, come ksh93 o Perl.

Se hai bisogno di array associativi in ​​una semplice shell POSIX, ecco un modo per simularli, quando i tasti sono limitati per contenere solo i caratteri 0-9A-Z_a-z(cifre ASCII, lettere e trattino basso). In base a questo presupposto, le chiavi possono essere utilizzate come parte dei nomi delle variabili. Le funzioni seguenti agiscono su un array identificato da un prefisso di denominazione, lo "stem", che non deve contenere due caratteri di sottolineatura consecutivi.

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(Avviso, codice non testato. Non viene fornito il rilevamento degli errori per chiavi e gambi sintatticamente non validi.)


5

Non sono sicuro di cosa intendi per negozio, ma puoi scorrere le chiavi usando la ${!array[@]}sintassi:

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

Quindi, per iterare:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

Ho trovato un breve tutorial su questo qui .


Come sottolineato nei commenti seguenti, gli array associativi sono stati aggiunti nella bashversione 4. Vedi qui per un articolo di rivista Linux sull'argomento.


1
(bash version 4 only)Questa è una cosa importante da notare. Tradizionalmente, le bashmatrici sono solo numeriche.
Ricky Beam,

1
Potresti voler utilizzare typesetinvece che declarenei tuoi esempi. Ciò li renderebbe portatili tra bash 4 e ksh93 che per primi hanno implementato array associativi di shell.
jlliagre,

0

Conchiglie senza array associativi

Non è così difficile quando i tasti sono limitati a [0-9A-Za-z_](numeri, lettere, trattino basso).

Il trucco è invece di archiviare nell'array [ $ key ], archiviare nelle variabili array_ $ key .

Impostato:

eval "array_$key='$value'"

Ottenere:

value=`eval echo '$'array_$key`

Nota: i valori non possono contenere '(virgoletta singola).


-1

questo funziona in bash

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

O

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

Non è necessario utilizzare eval afaik


1
Credo che tu abbia perso il punto della domanda.
G-Man dice "Ripristina Monica" il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.