0Pricing
Linux Command Line & Bash Scripting Mastery · Lección

Agregación con arrays y agrupación en awk

Calcule sumas, conteos y resúmenes agrupados mediante arrays asociativos cuyas claves sean valores de campos.

Agregación con arrays y agrupación en awk es una lección gratuita de Linux Command Line & Bash Scripting Mastery en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Linux Command Line & Bash Scripting Mastery, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Linux Command Line & Bash Scripting Mastery incluye 4 lecciones en total.

¿Qué son los arrays asociativos de awk?

En awk, un array asociativo es un almacén de pares clave-valor en el que las claves pueden ser cualquier cadena o número. A diferencia de los arrays indexados de la mayoría de los lenguajes, los arrays de awk son tablas hash internamente, lo que los hace perfectos para agrupar y agregar datos por valores de campo.

  • Declaración implícita: basta con asignar arr[key] = value
  • Las claves son cadenas de forma predeterminada (los números se convierten)
  • No hay límite de tamaño: awk amplía el array según sea necesario
  • Son ideales para calcular sumas, recuentos y totales agrupados en una sola pasada

No necesita inicializar una clave antes de incrementarla: awk trata automáticamente una clave no establecida como cero o como una cadena vacía.

Contar líneas por grupo

El patrón de agregación más común consiste en contar cuántas veces aparece cada valor único de un campo. Use el campo $1 (o cualquier otro campo) como clave del array e incremente un contador en cada fila coincidente.

El bloque END se ejecuta después de consumir toda la entrada; ese es el lugar donde debe imprimir los resultados acumulados.

count[$1]++

Después del procesamiento, count contiene el número total de líneas de cada valor único de $1.

#!/usr/bin/env bash
# Count how many log entries exist per HTTP status code
# Input format: <ip> <date> <method> <path> <status> <bytes>
printf '10.0.0.1 2024-01-01 GET /index 200 512
10.0.0.2 2024-01-01 POST /api 404 128
10.0.0.3 2024-01-01 GET /img 200 2048
10.0.0.4 2024-01-01 GET /api 500 64
10.0.0.5 2024-01-01 DELETE /api 404 32
' | awk '
{
    count[$5]++
}
END {
    for (status in count)
        print status, count[status]
}'

Sumar un campo numérico por grupo

Contar es solo una forma de agregación. Para sumar un campo numérico agrupado por otro campo, acumule el valor numérico en un array cuya clave sea el campo de agrupación.

El patrón es:

  • Clave = el campo por el que se agrupa (por ejemplo, $1 para el nombre de usuario)
  • Valor = el total acumulado del campo numérico (por ejemplo, $2 para los bytes)

Esto calcula una suma completa por grupos en una sola pasada de awk, sin necesidad de ordenar ni preprocesar los datos.

#!/usr/bin/env bash
# Sum bytes transferred per user from an access log
printf 'alice 1024
bob 512
alice 2048
charlie 256
bob 768
alice 128
' | awk '
{
    bytes[$1] += $2
}
END {
    for (user in bytes)
        printf "%-10s %d bytes\n", user, bytes[user]
}'

Combinar recuento y suma en una sola pasada

awk permite mantener varios arrays simultáneamente, lo que le proporciona el recuento y la suma (y, por tanto, el promedio) de cada grupo en un solo recorrido del archivo. Esto es mucho más eficiente que ejecutar la canalización dos veces.

  • count[key]++ — registra las apariciones
  • total[key] += $N — registra la suma acumulada
  • En END, divida total[k] / count[k] para obtener el promedio de cada grupo
#!/usr/bin/env bash
# Compute per-department headcount and average salary
printf 'Engineering Alice 95000
Engineering Bob 88000
Marketing Carol 72000
Marketing Dave 68000
Engineering Eve 102000
Marketing Frank 75000
' | awk '
{
    dept  = $1
    sal   = $3
    count[dept]++
    total[dept] += sal
}
END {
    printf "%-15s %5s %10s\n", "Department", "Count", "Avg Salary"
    for (d in count)
        printf "%-15s %5d %10.0f\n", d, count[d], total[d]/count[d]
}'

Claves de varios campos para agrupar en 2 dimensiones

Puede crear una clave compuesta concatenando varios campos con un separador. Esto permite agrupar en dos dimensiones sin ninguna sintaxis especial.

Elija un separador que no pueda aparecer en los datos (por ejemplo, SUBSEP, el separador de registros integrado de awk \034 o una barra vertical literal |).

  • Clave compuesta: arr[$1 SUBSEP $2] o arr[$1"|"$2]
  • Dividir la clave de nuevo al imprimir: split(key, parts, "|")
#!/usr/bin/env bash
# Count requests grouped by HTTP method AND status code
printf 'GET 200
POST 201
GET 404
GET 200
DELETE 204
POST 201
GET 404
POST 500
' | awk '
{
    key = $1 "|" $2
    count[key]++
}
END {
    printf "%-8s %-6s %s\n", "Method", "Status", "Count"
    for (k in count) {
        split(k, parts, "|")
        printf "%-8s %-6s %d\n", parts[1], parts[2], count[k]
    }
}'

Seguir los valores mínimo y máximo por grupo

Los arrays asociativos facilitan el seguimiento de los valores mínimo y máximo por grupo. El truco consiste en inicializarlos solo la primera vez que aparece cada clave mediante la condición especial !(key in arr).

  • !(key in min_arr) es verdadera la primera vez que se encuentra una clave
  • Después de la inicialización, compare y sobrescriba con la comprobación estándar de menor que / mayor que

Este patrón evita un cero espurio que alteraría el valor mínimo.

#!/usr/bin/env bash
# Find min and max response time per endpoint
printf '/api/users 120
/api/orders 340
/api/users 98
/api/orders 512
/api/users 210
/api/orders 280
/health 5
/health 7
' | awk '
{
    ep  = $1
    rt  = $2
    if (!(ep in mn)) { mn[ep] = rt; mx[ep] = rt }
    if (rt < mn[ep]) mn[ep] = rt
    if (rt > mx[ep]) mx[ep] = rt
}
END {
    printf "%-15s %6s %6s\n", "Endpoint", "Min", "Max"
    for (ep in mn)
        printf "%-15s %6d %6d\n", ep, mn[ep], mx[ep]
}'

Distribución de frecuencias: grupos principales

Una tarea habitual en el mundo real es encontrar los N valores más frecuentes. awk se encarga del recuento; canalice la salida mediante sort y head para ordenarla y limitarla.

Este patrón de canalización es idiomático en la ingeniería de shell:

  1. awk cuenta las apariciones en un array e imprime count key en END
  2. sort -rn ordena numéricamente en orden descendente
  3. head -n 5 conserva solo los 5 primeros

Mantener awk centrado en la agregación y delegar la ordenación a sort sigue la filosofía de Unix.

#!/usr/bin/env bash
# Top 3 most active IP addresses from an access log
printf '192.168.1.10 GET /index
10.0.0.5 POST /api
192.168.1.10 GET /css
172.16.0.3 GET /index
10.0.0.5 GET /api
192.168.1.10 DELETE /api
172.16.0.3 POST /login
10.0.0.5 GET /index
10.0.0.5 POST /logout
' | awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' \
  | sort -rn \
  | head -n 3

Usar NR y FNR para agregar datos de varios archivos

Al procesar varios archivos, los valores integrados de awk NR (total de registros leídos) y FNR (registros del archivo actual) le permiten identificar de qué archivo procede cada registro mediante FILENAME.

  • FILENAME — nombre del archivo que se está leyendo
  • FNR == 1 — se activa al comienzo de cada archivo nuevo (es útil para omitir encabezados)

Esto permite realizar agregaciones por grupos y por archivo en un directorio completo de registros con una sola invocación de awk.

Imprimir la salida ordenada de los arrays de awk

El bucle for (key in array) de awk no garantiza ningún orden. Para obtener una salida determinista, canalice la impresión del bloque END de awk hacia sort o recopile los valores y ordénelos dentro de awk mediante las funciones asorti / asort (solo GNU awk).

Para scripts multiplataforma, normalmente se prefiere el enfoque portátil basado en una canalización de shell:

  • sort -k1,1 — ordena alfabéticamente por el primer campo (la clave del grupo)
  • sort -k2,2rn — ordena numéricamente en orden descendente por el segundo campo (recuento o suma)
#!/usr/bin/env bash
# Bytes per user, sorted alphabetically by username
printf 'zara 800
alice 1500
bob 300
alice 200
zara 400
bob 1100
' | awk '
{
    total[$1] += $2
}
END {
    for (u in total)
        print u, total[u]
}' | sort -k1,1

Eliminar claves de arrays y restablecer el estado

A veces necesita restablecer el estado de agregación durante el procesamiento; por ejemplo, al procesar archivos de registro en los que cada sección está separada por una línea en blanco o por un valor centinela.

  • delete arr[key] — elimina una sola entrada
  • delete arr — vacía todo el array (GNU awk)
  • Compruebe la existencia con (key in arr) antes de acceder para evitar crear entradas fantasma

Esta técnica permite realizar agregaciones en una ventana deslizante o por sección sin reiniciar awk.

#!/usr/bin/env bash
# Sum values within each section delimited by "---"
printf 'alice 100
bob 200
---
alice 50
bob 75
charlie 300
---
' | awk '
/^---/ {
    print "-- Section totals --"
    for (u in total) printf "  %-10s %d\n", u, total[u]
    delete total
    next
}
{
    total[$1] += $2
}'

Canalización del mundo real: resumen de registros de Nginx

Al combinarlo todo, esta es una agregación de calidad de producción en una sola pasada de awk sobre un formato de registro combinado de Nginx. Calcula el recuento de solicitudes, el total de bytes y la tasa de errores por host virtual en un solo recorrido.

Técnicas principales utilizadas:

  • Clave compuesta: vhost extraído de un campo
  • Arrays paralelos: reqs[], bytes[], errors[]
  • Acumulación condicional: $9 >= 400 para contar solo las respuestas con error
  • Tabla con formato mediante printf en END
#!/usr/bin/env bash
# Simulated Nginx combined log: host ip - - [date] "METHOD /path HTTP/1.1" status bytes
printf 'api.example.com 10.0.0.1 - - [01/Jan/2024] "GET /v1" 200 1024
www.example.com 10.0.0.2 - - [01/Jan/2024] "GET /" 200 4096
api.example.com 10.0.0.3 - - [01/Jan/2024] "POST /v1" 500 128
www.example.com 10.0.0.4 - - [01/Jan/2024] "GET /img" 404 64
api.example.com 10.0.0.5 - - [01/Jan/2024] "GET /v1" 200 2048
www.example.com 10.0.0.6 - - [01/Jan/2024] "GET /" 200 4096
api.example.com 10.0.0.7 - - [01/Jan/2024] "DELETE /v1" 403 32
' | awk '
{
    host = $1; status = $9; b = $10
    reqs[host]++
    bytes[host] += b
    if (status + 0 >= 400) errors[host]++
}
END {
    printf "%-20s %6s %10s %6s\n", "Host", "Reqs", "Bytes", "Errors"
    for (h in reqs)
        printf "%-20s %6d %10d %6d\n", h, reqs[h], bytes[h], errors[h]+0
}'

Comprobación de conocimientos: inicializar min correctamente

Compruebe su comprensión de un error habitual en la agregación con awk.

Repaso de la lección: agregación con arrays de awk

Ha aprendido los patrones fundamentales para calcular agregaciones por grupos completamente dentro de awk:

  • Recuento: count[$key]++ — incremente en cada fila e imprima en END
  • Suma: total[$key] += $N — acumule los campos numéricos por grupo
  • Promedio: mantenga count[] y total[] y divida en END
  • Mínimo/máximo: inicialice en la primera aparición mediante !(key in arr) y después compare
  • Claves compuestas: concatene campos con un separador para agrupar en varias dimensiones
  • Salida ordenada: canalice la impresión de END de awk hacia sort para obtener un orden determinista
  • Restablecimiento de secciones: use delete arr para borrar el estado entre secciones lógicas de la entrada

Estos patrones le permiten sustituir consultas complejas a bases de datos o varias pasadas de una canalización por una sola invocación eficiente de awk, una habilidad esencial para la ingeniería de shell en entornos de producción.

Preguntas frecuentes

¿La lección «Agregación con arrays y agrupación en awk» es gratis?

Sí — el texto completo de «Agregación con arrays y agrupación en awk» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Linux Command Line & Bash Scripting Mastery, actualiza a CoddyKit PRO. El curso de Linux Command Line & Bash Scripting Mastery incluye 4 lecciones en total.

¿Qué aprenderé en «Agregación con arrays y agrupación en awk»?

Calcule sumas, conteos y resúmenes agrupados mediante arrays asociativos cuyas claves sean valores de campos. Practicas Linux Command Line & Bash Scripting Mastery con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Linux Command Line & Bash Scripting Mastery?

No se requiere experiencia previa. Linux Command Line & Bash Scripting Mastery en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Agregación con arrays y agrupación en awk»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Linux Command Line & Bash Scripting Mastery?

Sí. Cada lección de Linux Command Line & Bash Scripting Mastery incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Registros, campos y separadores personalizados en awk
  2. Patrones, rangos y bloques BEGIN/END
  3. Agregación con arrays y agrupación en awk
  4. Funciones de awk, formato con printf y generación de informes
← Volver a Linux Command Line & Bash Scripting Mastery