Saltar al contenido

matrices asociativas anidadas en bash

Agradecemos tu apoyo para difundir nuestras secciones sobre las ciencias informáticas.

Solución:

Esta es la mejor forma no pirateada de hacerlo, pero solo está limitado a acceder a elementos individuales. El uso de referencias de expansión de variables indirectas es otro, pero aún tendría que almacenar cada conjunto de elementos en un array. Si desea tener algún tipo de matrices anónimas, necesitará un generador de nombres de parámetros aleatorios. Si no usa un nombre aleatorio para un array, entonces no tiene sentido hacer referencia a él en asociativo array. Y, por supuesto, no me gustaría usar herramientas externas para generar nombres de variables anónimos aleatorios. Sería gracioso quien lo hiciera.

#!/bin/bash

a=(a aa)
b=(b bb bbb)
c=(c cc ccc cccc)

declare -A letters

function store_array 
    local var=$1 base_key=$2 values=("$@:3")
    for i in "$!values[@]"; do
        eval "$1[$base_key

store_array letters a "$a[@]"
store_array letters b "$b[@]"
store_array letters c "$c[@]"

echo "$1]"

Creo que la respuesta más sencilla es “No, las matrices bash no se pueden anidar”. Cualquier cosa que simule matrices anidadas en realidad es simplemente crear funciones de mapeo sofisticadas para el espacio de teclas de las matrices (de una sola capa).

No es que eso sea malo: puede ser exactamente lo que quieres, pero especialmente cuando no controlas el keys en tu array, hacerlo correctamente se vuelve más difícil. Aunque me gusta la solución dada por @konsolebox de usar un delimitador, finalmente se cae si su espacio de teclas incluye keys me gusta "p|q". Tiene la ventaja de que puede operar de forma transparente en su keys, como en array[abc|def] para buscar el key def en array[abc], que es muy claro y legible. Porque se basa en que el delimitador no aparece en el keys, este es solo un buen enfoque cuando sabe cómo se ve el espacio de teclas ahora y en todos los usos futuros del código. Esta es solo una suposición segura cuando tiene un control estricto sobre los datos.

Si necesita algún tipo de robustez, le recomendaría concatenar hashes de su array keys. Esta es una técnica simple que es muy probable que elimine los conflictos, aunque son posibles si trabaja con datos elaborados con mucho cuidado.

Para tomar prestado un poco de cómo Git maneja los hashes, tomemos los primeros 8 caracteres de las sumas sha512 de keys como nuestro hash keys. Si se siente nervioso por esto, siempre puede usar el sha512sum completo, ya que no se conocen colisiones para sha512. El uso de la suma de comprobación completa asegura que esté seguro, pero es un poco más engorroso.

Entonces, si quiero la semántica de almacenar un elemento en array[abc][def] lo que debo hacer es almacenar el valor en array["$(keyhash "abc")$(keyhash "def")"] donde keyhash Se ve como esto:

function keyhash ()  cut -c-8

A continuación, puede extraer los elementos del asociativo array usando el mismo keyhash función. Curiosamente, hay una versión memorizada de keyhash que puedes escribir que usa un array para almacenar los hashes, evitando llamadas adicionales a sha512sum, pero se vuelve costoso en términos de memoria si el script toma muchos keys:

declare -A keyhash_array
function keyhash () 
    if [ "$keyhash_array["$1"]" == "" ];
    then
        keyhash_array["$1"]="$(echo "$1" 

Una inspección de longitud en un determinado key me dice cuántas capas de profundidad mira en el array, ya que eso es solo len/8, y puedo ver las subclaves de un “anidado array”por listado keys y recortando aquellos que tienen la correcta prefix. Entonces, si quiero todos los keys en array[abc], lo que realmente debería hacer es esto:

for key in "$!array[@]"
do
    if [[ "$key" == "$(keyhash "abc")"* ]];
    then
        # do stuff with "$key" since it's a key directly into the array
        :
    fi
done

Curiosamente, esto también significa que el primer nivel keys son válidos y pueden contener valores. Entonces, array["$(keyhash "abc")"] es completamente válido, lo que significa que este “anidado array”La construcción puede tener una semántica interesante.

De una forma u otra, cualquier solución para matrices anidadas en Bash está utilizando exactamente este mismo truco: producir una función de mapeo (con suerte inyectiva) f(key,subkey) que produce cadenas que se pueden utilizar como array keys. Esto siempre se puede aplicar más como f(f(key,subkey),subsubkey) o, en el caso del keyhash función anterior, prefiero definir f(key) y aplicar a las subclaves como concat(f(key),f(subkey)) y concat(f(key),f(subkey),f(subsubkey)). En combinación con memorización para f, esto es mucho más eficiente. En el caso de la solución delimitador, las aplicaciones anidadas de f son necesarios, por supuesto.

Con eso conocido, la mejor solución que conozco es tomar un pequeño hash del key y subkey valores.


Reconozco que hay una aversión generalizada a las respuestas del tipo “¡Lo estás haciendo mal, usa esta otra herramienta!” pero las matrices asociativas en bash son desordenadas en numerosos niveles y te causan problemas cuando intentas portar el código a una plataforma que (por alguna razón tonta u otra) no tiene bash, o tiene un antiguo (pre-4 .x) versión. Si está dispuesto a buscar en otro idioma para sus necesidades de secuencias de comandos, le recomiendo que elija un poco de awk.

Proporciona la simplicidad de los scripts de shell con la flexibilidad que viene con más lenguajes ricos en funciones. Hay algunas razones por las que creo que esta es una buena idea:

  • GNU awk (la variante más frecuente) tiene matrices asociativas completamente desarrolladas que pueden anidar correctamente, con la sintaxis intuitiva de array[key][subkey]
  • Puede incrustar awk en scripts de shell, por lo que aún obtiene las herramientas del shell cuando realmente las necesita
  • awk es estúpidamente simple a veces, lo que lo pone en marcado contraste con otros lenguajes de reemplazo de shell como Perl y Python

Eso no quiere decir que awk esté libre de defectos. Puede ser difícil de entender cuando lo está aprendiendo por primera vez porque está muy orientado al procesamiento de secuencias (muy parecido a sed), pero es una gran herramienta para muchas tareas que apenas están fuera del alcance del shell.

Tenga en cuenta que antes dije que “GNU awk” (gawk) tiene matrices multidimensionales. Otros awks realmente hacen el truco de separar keys con un separador bien definido, SUBSEP. Puede hacerlo usted mismo, como con el array[a|b] solución en bash, pero nawk tiene esta función incorporada si lo hace array[key,subkey]. Todavía es un poco más fluido y claro que el de bash. array sintaxis.

Aquí puedes ver las reseñas y valoraciones de los lectores

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *