Cómo crear y utilizar hashes en Bash

Índice de Contenido
  1. Cómo crear y llenar hashes en Bash
    1. Cómo crear y llenar hashes en Bash
    2. Cómo procesar hashes
    3. Cómo ordenar hashes
    4. Hashes multi-nivel

Cómo crear y llenar hashes en Bash

En Bash, un hash es una estructura de datos que puede contener muchas subvariables, del mismo o diferentes tipos, pero las indexa con cadenas de texto personalizadas o claves en lugar de identificadores numéricos fijos. Además de ser extremadamente flexibles, los hashes también hacen que los scripts sean más legibles. Si necesitas procesar las áreas de ciertos países, por ejemplo, una sintaxis como:

print area_of('Germany')

sería tan autodocumentada como puede ser, ¿verdad?

Cómo crear y llenar hashes en Bash

Los hashes en Bash deben declararse con el interruptor en mayúsculas A (que significa Matriz Asociativa) y luego se pueden llenar listando todos sus pares clave/valor con esta sintaxis:

# Áreas de los países, en millas cuadradas
declare -A area_of
area_of=( [Italy]="116347" [Germany]="137998" [France]="213011" [Poland]="120728" [Spain]="192476" )

Lo primero que hay que notar aquí es que el orden en el que se declaran los elementos no importa. La shell simplemente lo ignora y almacena todo según sus propios algoritmos internos. Como prueba, esto es lo que sucede cuando se recuperan esos datos tal como se almacenaron:

print ${area_of[*]}
213011 120728 137998 192476 116347
print ${!area_of[*]}
France Poland Germany Spain Italy

De forma predeterminada, el asterisco dentro de los corchetes extrae todos y solo los valores de un hash. Agregar el signo de exclamación, en su lugar, recupera las claves del hash. Pero en ambos casos no hay un orden fácilmente reconocible.

Qué es Scrum y por qué tu negocio lo necesita

También puedes llenar un hash dinámicamente llamando a otros programas. Si, por ejemplo, tuvieras otro script de shell llamado generador-de-hashes, que produce la lista de pares como una cadena formateada adecuadamente:

#! /bin/bash
printf '[Italy]="116347" [Germany]="137998" [France]="213011" [Poland]="120728" [Spain]="192476"'
llamar al generador-de-hashes de esta manera desde el script que realmente utiliza el hash area_of:
VALS=$( generador-de-hashes )
eval declare -A area_of=( $VALS )

llenará ese hash con las mismas claves y valores. Por supuesto, aquí el mensaje es que "generador-de-hashes" puede ser cualquier programa, tal vez mucho más poderoso que Bash, siempre que pueda producir datos en ese formato. Para llenar un hash con el contenido de un archivo de texto plano existente, por el contrario, sigue estas sugerencias de Stack Overflow.

Cómo procesar hashes

La sintaxis exacta para hacer referencia a un elemento específico de un hash, o eliminarlo, es la siguiente:

print ${area_of['Germany']}
unset ${area_of['Germany']}

Para borrar todo un hash, simplemente pasa solo su nombre a unset y luego vuelve a declararlo:

unset area_of
declare -A area_of

El número de pares clave/valor almacenados en un hash se guarda en la variable especial llamada "${#NOMBREHASH[@]}" (no me mires a mí, yo no inventé esta sintaxis). Pero si todo lo que necesitas es procesar todos los elementos de un hash, independientemente de su número u orden interno, solo sigue este ejemplo:

for país in "${!area_of[@]}"
do
echo "Área de $país: ${area_of[$país]}"
done

cuyo resultado es:

Cómo utilizar el archivo .dockerignore para optimizar tus builds de Docker

Área de Francia: 213011 millas cuadradas

Área de Polonia: 120728 millas cuadradas

Área de Alemania: 137998 millas cuadradas

Se puede utilizar básicamente el mismo procedimiento para crear un hash "espejo", con las claves y valores invertidos:

declare -A país_cuya_área_es
for país in "${!area_of[@]}"; do
país_cuya_área_es[${area_of[$país]}]=$país
done

Entre otras cosas, este "espejo" puede ser la forma más fácil de procesar el hash original observando sus valores, en lugar de las claves.

Cómo ordenar hashes

Si los elementos del hash se almacenan en secuencias semirandom, ¿cuál es la forma más eficiente de manejarlos en cualquier orden alfanumérico? La respuesta es que depende de qué se deba ordenar exactamente y cuándo. En muchos casos, cuando lo único que se debe ordenar es la salida final de un bucle, y todo lo que se necesita hacer es un comando de ordenamiento justo después del cierre del bucle:

Cómo habilitar múltiples contenedores de Linux en Chrome OS
for país in "${!area_of[@]}"
do
  echo "$país: ${area_of[$país]}"
done | sort

Para ordenar la salida por clave (¡incluso si las claves no se recuperaron en ese orden!):

Alemania: 137998 millas cuadradas

Francia: 213011 millas cuadradas

Italia: 116347 millas cuadradas

Ordenando las mismas líneas numéricamente, por área del país, es casi tan fácil. Al agregar las áreas al principio de cada línea:

for aa in "${!area_of[@]}"
 do
 printf "%s|%s = %s millas cuadradas
" "${area_of[$aa]}" "$aa" "${area_of[$aa]}"
 done

se obtienen líneas como estas:

Las mejores plataformas de integración y entrega continua (CI/CD) para desarrollo de software

213011|Francia = 213011 millas cuadradas

120728|Polonia = 120728 millas cuadradas

137998|Alemania = 137998 millas cuadradas

que, aunque todavía no están ordenadas, ahora empiezan con las cadenas en las que queremos ordenar. Por lo tanto, al usar sort nuevamente, pero con una canalización al comando cut con "|" como separador de columnas:

1 for aa in "${!area_of_generated[@]}"
2 do
3 printf "%s|%s = %s millas cuadradas
" "${area_of_generated[$aa]}" "$aa" "${area_of_generated[$aa]}"
4 done | sort | cut '-d|' -f2-

se ordenará por áreas y luego se eliminarán, para finalmente producir el resultado deseado:

Italia = 116347 millas cuadradas

Cómo crear y desplegar rápidamente un repositorio Git usando git y ssh

Polonia = 120728 millas cuadradas

Alemania = 137998 millas cuadradas

Hashes multi-nivel

Aunque Bash no admite hashes anidados de múltiples niveles, es posible emularlos con algunas matrices auxiliares. Considera este código, que almacena las áreas de las regiones europeas, al mismo tiempo que las cataloga por país:

1  declare -a regiones_europeas=('Baviera' 'Lacio' 'Sajonia' 'Toscana')
 2  declare -a países_europeos=('Italia' 'Alemania')
 3  declare -A áreas_de_region_del_país
 4  áreas_de_region_del_país=( [Lacio en Italia]="5000" [Toscana en Italia]="6000" [Baviera en Alemania]="9500" [Sajonia en Alemania]="7200" )
 5  
 6  for país in "${países_europeos[@]}"
 7  do
 8   for región in "${regiones_europeas[@]}"
 9     do
10       cr="$región en $país"
11       if test "${áreas_de_region_del_país[$cr]+isset}"
12         then
13         printf "Área de %-20.20s: %s
" "$cr" "${áreas_de_region_del_país[$cr]}"
14         fi
15     done
16  done

El código crea dos arrays normales, uno para países y otro para regiones, además de un hash con claves compuestas que asocia cada región a su país y emula un hash de dos niveles. Luego, el código genera todas las combinaciones posibles de regiones y países, pero solo procesa los elementos existentes de áreas_de_region_del_país, reconocidos con la prueba *isset de la línea 11. ¡Robusto, pero efectivo!

Las mejores lenguajes de programación para 2022: Python

En Newsmatic nos especializamos en tecnología de vanguardia, contamos con los artículos mas novedosos sobre Desarrollo, allí encontraras muchos artículos similares a Cómo crear y utilizar hashes en Bash , tenemos lo ultimo en tecnología 2023.

Artículos Relacionados

Subir

Utilizamos cookies para mejorar su experiencia de navegación, mostrarle anuncios o contenidos personalizados y analizar nuestro tráfico. Al hacer clic en “Aceptar todo” usted da su consentimiento a nuestro uso de las cookies.