Dando per scontato che desidera limitare a Bourne-come conchiglie (molti altri shells Ti piace csh
, tcsh
, rc
, es
o fish
matrici di supporto, ma scrivendo uno script compatibili allo stesso tempo di shell Bourne-like e chi è ingannevole e, in generale inutile in quanto sono interpreti per completamente diverso e linguaggi incompatibili), si noti che esistono differenze significative tra le implementazioni.
Le shell tipo Bourne che supportano gli array sono:
ksh88
(Questo è il primo ad implementare array, ksh88 si trova ancora come ksh
nella maggior parte degli Unici commerciali tradizionali dove è anche la base per sh
)
- le matrici sono monodimensionali
- Le matrici sono definite come
set -A array foo bar
o set -A array -- "$var" ...
se non è possibile garantire che $var
non inizieranno con un -
o +
.
- Gli indici di array iniziano alle
0
.
- I singoli elementi dell'array sono assegnati come
a[1]=value
.
- le matrici sono sparse. Funzionerà
a[5]=foo
anche se a[0,1,2,3,4]
non sono impostati e li lascerà non impostati.
${a[5]}
per accedere all'elemento indice 5 (non necessariamente al sesto elemento se l'array è scarso). La 5
non ci può essere qualsiasi espressione aritmetica.
- la dimensione e la sottoscrizione dell'array sono limitate (a 4096).
${#a[@]}
è il numero di elementi assegnati nell'array (non il massimo indice assegnato).
- non è possibile conoscere l'elenco degli indici assegnati (se non quello di testare individualmente i 4096 elementi
[[ -n "${a[i]+set}" ]]
).
$a
è lo stesso di ${a[0]}
. Cioè gli array in qualche modo estendono le variabili scalari dando loro valori extra.
pdksh
e derivati (questa è la base per ksh
e talvolta sh
di diversi BSD ed era l'unica implementazione open source di ksh prima che la fonte ksh93 fosse liberata):
Principalmente come ksh88
ma nota:
- Alcune vecchie implementazioni non supportavano
set -A array -- foo bar
( --
non era necessario lì).
${#a[@]}
è uno più l'indice del massimo indice assegnato. ( a[1000]=1; echo "${#a[@]}"
genera 1001 anche se l'array ha solo un elemento.
- nelle versioni più recenti, la dimensione dell'array non è più limitata (tranne che dalla dimensione degli interi).
- le versioni recenti di
mksh
avere pochi operatori in più ispirate da bash
, ksh93
o zsh
come le assegnazioni a la a=(x y)
, a+=(z)
, ${!a[@]}
per ottenere l'elenco degli indici assegnati.
zsh
. zsh
le matrici sono generalmente progettate meglio e prendono il meglio ksh
e le csh
matrici. Sono simili ksh
ma con differenze significative:
- gli indici iniziano da 1, non da 0 (tranne che
ksh
nell'emulazione), in linea con l'array Bourne (i parametri di posizione $ @, che zsh
espone anche come array $ argv) e gli csh
array.
- sono un tipo separato dalle variabili normali / scalari. Gli operatori si applicano in modo diverso a loro e come ti aspetteresti generalmente.
$a
non è lo stesso di ${a[0]}
ma si espande negli elementi non vuoti dell'array ( "${a[@]}"
per tutti gli elementi come in ksh
).
- sono matrici normali, non matrici sparse.
a[5]=1
funziona ma assegna a tutti gli elementi da 1 a 4 la stringa vuota se non sono stati assegnati. Quindi ${#a[@]}
(lo stesso del ${#a}
quale in ksh è la dimensione dell'elemento di indice 0) è il numero di elementi nell'array e il massimo indice assegnato.
- matrici associative sono supportate.
- è supportato un gran numero di operatori per lavorare con array, troppo grandi per essere elencati qui.
- matrici definite come
a=(x y)
. set -A a x y
funziona anche, ma set -A a -- x y
non è supportato se non nell'emulazione ksh ( --
non è necessaria nell'emulazione zsh).
ksh93
. (qui che descrivono le ultime versioni). ksh93
, considerato a lungo sperimentale ora può essere trovato in sempre più sistemi ora che è stato rilasciato come FOSS. Ad esempio, è il /bin/sh
(dove ha sostituito la shell Bourne /usr/xpg4/bin/sh
, la shell POSIX è ancora basata su ksh88
) e ksh
di Solaris 11
. I suoi array si estendono e migliorano quelli di ksh88.
a=(x y)
può essere usato per definire una matrice, ma poiché a=(...)
viene anche usato per definire variabili composte ( a=(foo=bar bar=baz)
), a=()
è ambiguo e dichiara una variabile composta, non una matrice.
- le matrici sono multidimensionali (
a=((0 1) (0 2))
) e gli elementi di matrice possono anche essere variabili composte ( a=((a b) (c=d d=f)); echo "${a[1].c}"
).
- Una
a=([2]=foo [5]=bar)
sintassi può essere utilizzata per definire array sparsi contemporaneamente.
- Limiti di dimensione sollevati.
- Non nella misura in cui
zsh
, ma un gran numero di operatori ha supportato anche per manipolare array.
"${!a[@]}"
per recuperare l'elenco di indici di array.
- matrici associative supportate anche come tipo separato.
bash
. bash
è la shell del progetto GNU. È usato come sh
nelle recenti versioni di OS / X e alcune distribuzioni GNU / Linux. bash
le matrici emulano principalmente ksh88
quelle con alcune caratteristiche di ksh93
e zsh
.
a=(x y)
supportato. set -A a x y
non supportato. a=()
crea un array vuoto (nessuna variabile composta in bash
).
"${!a[@]}"
per l'elenco degli indici.
a=([foo]=bar)
sintassi supportata e alcune altre da ksh93
e zsh
.
- le
bash
versioni recenti supportano anche array associativi come tipo separato.
yash
. Si tratta di un'implementazione sh POSIX relativamente recente, pulita e compatibile con più byte. Non ampiamente utilizzato. I suoi array sono un'altra API pulita simile azsh
- le matrici non sono sparse
- Gli indici di array iniziano da 1
- definito (e dichiarato) con
a=(var value)
- elementi inseriti, cancellati o modificati con l'
array
integrato
array -s a 5 value
la modifica del 5 ° elemento fallirebbe se quell'elemento non fosse stato assegnato in anticipo.
- il numero di elementi nell'array è
${a[#]}
, ${#a[@]}
essendo la dimensione degli elementi come un elenco.
- le matrici sono di tipo separato. È necessario
a=("$a")
ridefinire una variabile scalare come matrice prima di poter aggiungere o modificare elementi.
- le matrici non sono supportate quando invocate come
sh
.
Quindi, da questo puoi vedere quel rilevamento per il supporto dell'array, che potresti fare con:
if (unset a; set -A a a; eval "a=(a b)"; eval '[ -n "${a[1]}" ]'
) > /dev/null 2>&1
then
array_supported=true
else
array_supported=false
fi
non è sufficiente per poter usare quelle matrici. Dovresti definire i comandi wrapper per assegnare matrici come elementi interi e singoli e assicurarti di non tentare di creare matrici sparse.
Piace
unset a
array_elements() { eval "REPLY=\"\${#$1[@]}\""; }
if (set -A a -- a) 2> /dev/null; then
set -A a -- a b
case ${a[0]}${a[1]} in
--) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=0;;
a) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=1;;
--a) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
ab) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
esac
elif (eval 'a[5]=x') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0
elif (eval 'a=(x) && array -s a 1 y && [ "${a[1]}" = y ]') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() {
eval "
$1=(\${$1+\"\${$1[@]}"'"})
while [ "$(($2))" -ge "${'"$1"'[#]}" ]; do
array -i "$1" "$2" ""
done'
array -s -- "$1" "$((1+$2))" "$3"
}
array_elements() { eval "REPLY=\${$1[#]}"; }
first_indice=1
else
echo >&2 "Array not supported"
fi
E poi accedere con elementi dell'array "${a[$first_indice+n]}"
, l'intero elenco con "${a[@]}"
e utilizzare le funzioni wrapper ( array_elements
, set_array
, set_array_element
) per ottenere il numero di elementi di una matrice (a $REPLY
), impostare la matrice come un intero o assegnare singoli elementi.
Probabilmente non vale la pena. Userei perl
o limite alla matrice shell Bourne / POSIX: "$@"
.
Se l'intento è quello di avere alcuni file che devono essere forniti dalla shell interattiva di un utente per definire le funzioni che utilizzano internamente le matrici, ecco alcune altre note che potrebbero essere utili.
È possibile configurare gli zsh
array in modo che siano più simili agli ksh
array negli ambiti locali (in funzioni o funzioni anonime).
myfunction() {
[ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
# use arrays of indice 0 in this function
}
È inoltre possibile emulare ksh
(migliorare la compatibilità con ksh
array e diverse altre aree) con:
myfunction() {
[ -z "$ZSH_VERSION" ] || emulate -L ksh
# ksh code more likely to work here
}
Con questo in mente e si è disposti a rilasciare il supporto per yash
e ksh88
e le versioni precedenti di pdksh
derivati, e finché non si tenta di creare array sparsi, si dovrebbe essere in grado di utilizzare in modo coerente:
a[0]=foo
a=(foo bar)
(ma non a=()
)
"${a[#]}"
, "${a[@]}"
,"${a[0]}"
in quelle funzioni che hanno emulate -L ksh
, mentre l' zsh
utente usa ancora le sue matrici normalmente nel modo zsh.