Suponiendo que usted quiere restringir a Bourne como conchas (muchas otras cáscaras como csh
, tcsh
, rc
, es
o fish
matrices de apoyo, pero escribir un guión compatible al mismo tiempo a Bourne como conchas y los que es complicado y generalmente tiene sentido, ya que son intérpretes para completamente diferente y idiomas incompatibles), tenga en cuenta que existen diferencias significativas entre las implementaciones.
Los shells tipo Bourne que admiten matrices son:
ksh88
(esa es la primera implementación de matrices, ksh88 todavía se encuentra como ksh
en la mayoría de las unidades comerciales tradicionales donde también es la base sh
)
- las matrices son unidimensionales
- Las matrices se definen como
set -A array foo bar
o set -A array -- "$var" ...
si no puede garantizar que $var
no comenzará con una -
o +
.
- Los índices de matriz comienzan en
0
.
- Los elementos individuales de la matriz se asignan como
a[1]=value
.
- Las matrices son escasas. Eso
a[5]=foo
funcionará incluso si a[0,1,2,3,4]
no están configurados y los dejará sin configurar.
${a[5]}
para acceder al elemento del índice 5 (no necesariamente el sexto elemento si la matriz es escasa). El 5
puede haber cualquier expresión aritmética.
- El tamaño de la matriz y el subíndice están limitados (a 4096).
${#a[@]}
es el número de elemento asignado en la matriz (no el mayor índice asignado).
- no hay forma de conocer la lista de subíndices asignados (aparte de probar los elementos 4096 individualmente con
[[ -n "${a[i]+set}" ]]
).
$a
es el mismo que ${a[0]}
. Es decir, las matrices de alguna manera extienden las variables escalares dándoles valores adicionales.
pdksh
y derivados (esa es la base para, ksh
y algunas veces, sh
de varios BSD y fue la única implementación de código abierto de ksh antes de que se liberara la fuente de ksh93):
Principalmente como ksh88
pero tenga en cuenta:
- Algunas implementaciones antiguas no eran compatibles
set -A array -- foo bar
( --
no era necesario allí).
${#a[@]}
es uno más el índice del mayor índice asignado. ( a[1000]=1; echo "${#a[@]}"
salidas 1001 a pesar de que la matriz tiene solo un elemento.
- en versiones más nuevas, el tamaño de la matriz ya no está limitado (excepto por el tamaño de los enteros).
- Las versiones recientes de
mksh
tienen unos pocos operadores adicionales inspirados bash
, ksh93
o zsh
como asignaciones a la a=(x y)
, a+=(z)
, ${!a[@]}
para obtener la lista de índices asignados.
zsh
. zsh
matrices están generalmente mejor diseñados y toman lo mejor de ksh
y csh
matrices. Son similares ksh
pero con diferencias significativas:
- los índices comienzan en 1, no en 0 (excepto en la
ksh
emulación), eso es consistente con la matriz Bourne (los parámetros de posición $ @, que zsh
también se exponen como su matriz $ argv) y las csh
matrices.
- son un tipo separado de las variables normales / escalares. Los operadores se aplican de manera diferente a ellos y como generalmente esperarías.
$a
no es lo mismo ${a[0]}
pero se expande a los elementos no vacíos de la matriz ( "${a[@]}"
para todos los elementos como en ksh
).
- son matrices normales, no matrices dispersas.
a[5]=1
funciona pero asigna todos los elementos del 1 al 4 a la cadena vacía si no se asignaron. Entonces ${#a[@]}
(igual ${#a}
que en ksh es el tamaño del elemento del índice 0) es el número de elementos en la matriz y el índice asignado más grande.
- matrices asociativas son compatibles.
- Se admite una gran cantidad de operadores para trabajar con matrices, demasiado grande para enumerar aquí.
- matrices definidas como
a=(x y)
. set -A a x y
también funciona, pero set -A a -- x y
no es compatible a menos que en la emulación ksh ( --
no se necesita en la emulación zsh).
ksh93
. (Aquí se describen las últimas versiones). ksh93
, considerado experimental durante mucho tiempo, ahora se puede encontrar en más y más sistemas ahora que se ha lanzado como FOSS. Por ejemplo, es el /bin/sh
(donde reemplazó el shell Bourne /usr/xpg4/bin/sh
, el shell POSIX todavía se basa en ksh88
) y ksh
de Solaris 11
. Sus matrices amplían y mejoran los ksh88.
a=(x y)
se puede usar para definir una matriz, pero como a=(...)
también se usa para definir variables compuestas ( a=(foo=bar bar=baz)
), a=()
es ambigua y declara una variable compuesta, no una matriz.
- Las matrices son multidimensionales (
a=((0 1) (0 2))
) y los elementos de la matriz también pueden ser variables compuestas ( a=((a b) (c=d d=f)); echo "${a[1].c}"
).
- Se
a=([2]=foo [5]=bar)
puede usar una sintaxis para definir matrices dispersas a la vez.
- Limitaciones de tamaño levantadas.
- No en la medida de
zsh
, pero gran cantidad de operadores soportados también para manipular matrices.
"${!a[@]}"
para recuperar la lista de índices de matriz.
- Las matrices asociativas también se admiten como un tipo separado.
bash
. bash
es la cáscara del proyecto GNU. Se usa como sh
en versiones recientes de OS / X y algunas distribuciones de GNU / Linux. bash
Las matrices emulan principalmente ksh88
las que tienen algunas características de ksh93
y zsh
.
a=(x y)
soportado. set -A a x y
No es compatible. a=()
crea una matriz vacía (sin variables compuestas bash
).
"${!a[@]}"
para la lista de índices.
a=([foo]=bar)
sintaxis compatible, así como algunos otros de ksh93
y zsh
.
- Las
bash
versiones recientes también admiten matrices asociativas como un tipo separado.
yash
. Es una implementación POSIX sh relativamente reciente, limpia y con reconocimiento de varios bytes. No en uso amplio. Sus matrices son otra API limpia similar azsh
- las matrices no son escasas
- Los índices de matriz comienzan en 1
- definido (y declarado) con
a=(var value)
- elementos insertados, eliminados o modificados con el
array
incorporado
array -s a 5 value
para modificar el 5 º elemento fallaría si ese elemento no fue asignado de antemano.
- el número de elementos en la matriz es
${a[#]}
, ${#a[@]}
siendo el tamaño de los elementos como una lista.
- Las matrices son un tipo separado. Debe
a=("$a")
redefinir una variable escalar como una matriz antes de poder agregar o modificar elementos.
- Las matrices no son compatibles cuando se invoca como
sh
.
Entonces, a partir de eso, puede ver que la detección de soporte de matriz, que podría hacer 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
no es suficiente para poder usar esas matrices. Debería definir comandos de envoltura para asignar matrices como elementos completos e individuales, y asegurarse de no intentar crear matrices dispersas.
Me gusta
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
Y luego se accede a elementos de la matriz con "${a[$first_indice+n]}"
, toda la lista con "${a[@]}"
y utilizar las funciones de contenedor ( array_elements
, set_array
, set_array_element
) para obtener el número de elementos de un array (en $REPLY
), establecer la matriz como enteros o asignar un elementos individuales.
Probablemente no valga la pena el esfuerzo. Que haría uso perl
o límite a la matriz shell Bourne / POSIX: "$@"
.
Si la intención es que el shell interactivo de un usuario obtenga algún archivo para definir funciones que utilizan arrays internamente, aquí hay algunas notas más que pueden ser útiles.
Puede configurar las zsh
matrices para que se parezcan más a las ksh
matrices en ámbitos locales (en funciones o funciones anónimas).
myfunction() {
[ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
# use arrays of indice 0 in this function
}
También puede emular ksh
(mejorar la compatibilidad con ksh
matrices y varias otras áreas) con:
myfunction() {
[ -z "$ZSH_VERSION" ] || emulate -L ksh
# ksh code more likely to work here
}
Con esto en mente y que está dispuesto a soltar para yash
y ksh88
y versiones anteriores de pdksh
derivados, y siempre y cuando no se intenta crear matrices dispersas, que deben ser capaces de utilizar de manera uniforme:
a[0]=foo
a=(foo bar)
(pero no a=()
)
"${a[#]}"
` "${a[@]}"
`"${a[0]}"
en aquellas funciones que tienen emulate -L ksh
, mientras el zsh
usuario todavía usa sus matrices normalmente de la manera zsh.