Comando awk: imprimir campos, el delimitador -F y patrones condicionales

Entorno de pruebaFamilia RHELAlmaLinux 9.8Cuenta rootVerificado el 2026-10-29

El comando awk es una herramienta de Linux que lee un archivo de texto línea por línea, divide cada línea en campos por los espacios o por el delimitador que indiques, y selecciona solo los campos de las líneas que cumplen una condición para mostrarlos o calcular con ellos. En un servidor AlmaLinux 9, contamos las solicitudes por IP de origen y los casos por código de estado de un archivo de ejemplo de registro de acceso de un servidor web con una sola línea unida a sort mediante una tubería, y resultó que las tres respuestas 404 de las doce líneas eran solicitudes a wp-login.php y .env desde una misma IP.

La salida siguiente se obtuvo con la cuenta root dentro de una carpeta de trabajo en un servidor AlmaLinux 9.8. El registro de acceso, la lista de cuentas, los registros de ventas y el archivo de puntuaciones son archivos de ejemplo creados para las pruebas, y las direcciones IP y los nombres de cuenta que contienen también son valores de ejemplo.

1️⃣ Uso básico del comando awk

  • ↪️ Números de campo y print

awk divide cada línea leída por los espacios y numera los campos desde la izquierda como $1, $2, $3. Lo comprobamos con scores.txt, donde el nombre, el resultado y la puntuación están separados por espacios.

cat scores.txt
alice   pass  82
bob     fail  47
carol   pass  91
dave    pass  68
erin    fail  55

Las llaves dentro de las comillas simples contienen la acción que se ejecuta en cada línea, y si después de print enumeras números de campo separados por comas, solo salen esos campos. Al mostrar los campos primero y tercero quedan solo el nombre y la puntuación.

awk '{print $1, $3}' scores.txt
alice 82
bob 47
carol 91
dave 68
erin 55

Si quitas la coma entre campos y escribes $1 $3, los dos valores salen unidos sin espacio. La coma de print inserta el separador de salida (un espacio por defecto), y los valores escritos juntos sin coma se unen en una sola cadena.

awk '{print $1 $3}' scores.txt
alice82
bob47
carol91
dave68
erin55

NR es el número de la línea leída hasta el momento, y NF es el número de campos de esa línea. $NF indica el último campo, así que puedes elegir la última columna aunque el número de campos cambie de una línea a otra.

awk '{print NR, NF, $NF}' scores.txt
1 3 82
2 3 47
3 3 91
4 3 68
5 3 55

El registro de acceso de un servidor web también está separado por espacios, así que los campos se eligen de la misma forma. Los números de campo de la primera línea del registro de prueba son los siguientes.

CampoValor en la primera líneaSignificado
$1192.0.2.10IP de origen
$4[29/Oct/2026:00:01:12Fecha y hora de la solicitud
$6"GETMétodo de la solicitud (con comillas dobles delante)
$7/index.htmlURL de la solicitud
$9200Código de estado
$105120Bytes enviados
$11"-"Página anterior (Referer)
$12~$15"Mozilla/5.0 (X11; Linux x86_64)"Agente de usuario (se divide en cada espacio)

Mostramos $1, $7 y $9, que corresponden a la IP de origen, la URL de la solicitud y el código de estado.

awk '{print $1, $7, $9}' access.log
192.0.2.10 /index.html 200
198.51.100.7 /about.html 200
192.0.2.10 /images/logo.png 200
203.0.113.25 /wp-login.php 404
203.0.113.25 /wp-login.php 404
192.0.2.10 /contact.html 200
198.51.100.7 /old-page.html 301
203.0.113.25 /.env 404
192.0.2.44 /index.html 200
198.51.100.7 /api/search?q=awk 500
192.0.2.44 /images/logo.png 304
192.0.2.10 /index.html 200

Una columna con espacios en su valor, como el agente de usuario, se divide en varios campos. NF fue 15 en las tres primeras líneas, y $NF es el último fragmento del agente de usuario.

awk '{print NF, $NF}' access.log | head -3
15 x86_64)"
15 x86_64)"
15 x86_64)"

2️⃣ Indicar el delimitador con awk -F

  • ↪️ Delimitadores de dos puntos, coma y expresión regular

En un archivo cuyas columnas se separan con un símbolo que no es el espacio, escribe ese símbolo después de -F. Al mostrar $1 sin -F en la lista de cuentas users.txt, creada con la misma forma que /etc/passwd, la mayoría de las líneas salieron enteras.

awk '{print $1}' users.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
nobody:x:65534:65534:Kernel
user:x:1000:1000:Example
deploy:x:1001:1001:Deploy
backup:x:1002:1002::/home/backup:/sbin/nologin

El delimitador por defecto es el espacio, así que una línea unida solo por dos puntos tiene un único campo. Solo las líneas nobody, user y deploy, que tienen un espacio en la columna de descripción, se cortan en ese espacio.

Si indicas los dos puntos como delimitador con -F:, se separan el nombre de cuenta ($1) y el shell de inicio de sesión ($7).

awk -F: '{print $1, $7}' users.txt
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
nobody /sbin/nologin
user /bin/bash
deploy /bin/bash
backup /sbin/nologin

Los archivos CSV separados por comas se dividen con -F,. Al mostrar el artículo y la cantidad de los registros de ventas sales.csv, la cabecera de la primera línea (item qty) se divide igual y aparece también.

awk -F, '{print $2, $3}' sales.csv
item qty
keyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2

-F, no sirve para CSV con comas dentro de columnas entre comillas dobles. En quoted.csv, que tiene comas en la columna del artículo, los campos también se dividen en las comas entre comillas, y en el segundo campo queda solo la primera parte del nombre del artículo.

awk -F, '{print $2}' quoted.csv
item
"cable
keyboard

Para estos archivos, el manual oficial de GNU Awk explica cómo usar la variable FPAT. Si en lugar del delimitador escribes la forma de un campo como expresión regular, la columna entre comillas sale como un solo campo.

awk -v FPAT='([^,]*)|("[^"]*")' '{print $2}' quoted.csv
item
"cable, usb"
keyboard

Para usar varios delimitadores, escríbelos como expresión regular entre corchetes. Si indicas como delimitadores los dos puntos y la barra, $NF pasa a ser el último nombre de la ruta del shell de inicio de sesión (bash, nologin).

awk -F'[:/]' '{print $1, $NF}' users.txt
root bash
bin nologin
daemon nologin
nobody nologin
user bash
deploy bash
backup nologin

3️⃣ Patrones condicionales del comando awk

  • ↪️ Expresiones regulares, comparaciones y NR

Aunque elijas campos, se muestran todas las líneas, así que para dejar solo las que necesitas pon una condición (patrón) antes de las llaves. Una cadena entre barras selecciona solo las líneas que la contienen, y si omites la acción se muestra la línea entera.

awk '/wp-login/' access.log
203.0.113.25 - - [29/Oct/2026:00:04:51 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"
203.0.113.25 - - [29/Oct/2026:00:04:52 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"

Las líneas seleccionadas son las mismas que con el comando grep, y awk puede elegir directamente los campos de esas líneas y mostrarlos. Si pasas a awk por una tubería las mismas dos líneas seleccionadas con grep, quedan solo la IP y el código de estado.

grep wp-login access.log | awk '{print $1, $9}'
203.0.113.25 404
203.0.113.25 404

Los valores de los campos se comparan con ==, !=, >, >=, <, <=. Seleccionamos solo las líneas cuyo código de estado ($9) es 404 y mostramos la IP y la URL de la solicitud.

awk '$9 == 404 {print $1, $7}' access.log
203.0.113.25 /wp-login.php
203.0.113.25 /wp-login.php
203.0.113.25 /.env

Al comparar con una cadena, pon el valor entre comillas dobles. Seleccionamos solo los nombres cuyo segundo campo es pass.

awk '$2 == "pass" {print $1}' scores.txt
alice
carol
dave

La comparación numérica sirve para seleccionar por rangos, como con los números de cuenta (UID). Al seleccionar las cuentas con UID de 1000 o más, junto a las cuentas normales entra también nobody, cuyo UID es 65534.

awk -F: '$3 >= 1000 {print $1, $3}' users.txt
nobody 65534
user 1000
deploy 1001
backup 1002

Dos condiciones se unen con &&. Al añadir la condición de menos de 65534, nobody desaparece y quedan solo las tres cuentas normales y sus carpetas personales.

awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $6}' users.txt
user /home/user
deploy /home/deploy
backup /home/backup

[~] comprueba si un campo coincide con una expresión regular, y [!~] si no coincide. Al seleccionar por separado las cuentas cuyo shell de inicio de sesión ($7) termina en bash y las que no son nologin, salen las mismas tres cuentas.

awk -F: '$7 ~ /bash$/ {print $1}' users.txt
root
user
deploy
awk -F: '$7 !~ /nologin/ {print $1, $7}' users.txt
root /bin/bash
user /bin/bash
deploy /bin/bash

La condición NR selecciona por número de línea. Con NR > 1 se quita la cabecera del CSV y quedan solo los registros de ventas.

awk -F, 'NR > 1 {print $2, $3}' sales.csv
keyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2

La salida de otros comandos también se puede pasar por una tubería y dividir igual. Al elegir el tamaño ($5) y el nombre ($9) en la salida de ls -l, la primera línea salió vacía, porque la primera línea de ls -l, [total 24], no tiene campos quinto ni noveno.

ls -l | awk '{print $5, $9}'

1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txt

Al añadir NR > 1 desaparece la primera línea y quedan solo los tamaños y los nombres de archivo.

ls -l | awk 'NR > 1 {print $5, $9}'
1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txt

4️⃣ BEGIN y END de awk, sumas y promedios

  • ↪️ Variables y formatos de salida con printf

El bloque BEGIN se ejecuta una vez antes de leer la primera línea, y el bloque END una vez después de procesar la última. Para una suma, añade a una variable en cada línea y muéstrala en END. El diagrama siguiente muestra el orden que sigue awk en cada línea al sumar los importes de los registros de ventas.

🔁 Orden en que awk procesa sales.csv línea por línea
Diagrama explicativo
🔁 Orden de procesamiento
$ awk -F, 'NR > 1 {t += $3 * $4} END {printf "total %.2f\n", t}' sales.csv
① Línea leídaNR = 1date,item,qty,priceNR = 22026-10-01,keyboard,2,45.00NR = 32026-10-01,mouse,5,19.90NR = 82026-10-04,monitor,2,189.00No hay más líneas que leerLa línea 8 es la última.
② Dividir campos (-F,)$1date$2item$3qty$4priceLa línea de cabecera se divide igual.$12026-10-01$2keyboard$32$445.00$3 cantidad, $4 precio unitario$12026-10-01$2mouse$35$419.90$3 cantidad, $4 precio unitario$12026-10-04$2monitor$32$4189.00$3 cantidad, $4 precio unitarioNo hay línea que dividirEl bloque END no lee líneas.
③ Patrón y acciónNR > 1 falsoSe omite la acción.t = (vacío)NR > 1 verdaderot += 2 * 45.00t = 90NR > 1 verdaderot += 5 * 19.90t = 189.5NR > 1 verdaderot += 2 * 189.00t = 886.3Se ejecuta ENDtotal 886.30printf muestra t con dos decimales.
La primera línea es la cabecera, así que NR > 1 es falso y awk pasa a la línea siguiente sin ejecutar la acción.
Desde la segunda línea el patrón es verdadero, y 90, la cantidad por el precio unitario, se suma a la variable t.
La variable t conserva su valor de una línea a otra, así que el total hasta la tercera línea es 189.5.
Las líneas 4 a 7 siguen el mismo orden, y hasta la última, la línea 8, t llega a 886.3.
Después de procesar la última línea, el bloque END se ejecuta una vez y printf muestra total 886.30.

La suma de todos los bytes enviados ($10) del registro de acceso fue de 41298 bytes. Una variable usada por primera vez empieza vacía (0 como número), así que no hace falta ponerla a 0.

awk '{sum += $10} END {print sum}' access.log
41298

Si muestras la suma en la acción de cada línea en lugar de en END, cada línea muestra el total acumulado hasta ese momento. Si cada vez que sumas a t la cantidad por el precio muestras el número de línea y t, salen siete líneas sin la cabecera, y el 886.3 de la última línea es el total general.

awk -F, 'NR > 1 {t += $3 * $4; print NR, t}' sales.csv
2 90
3 189.5
4 378.5
5 423.5
6 468.5
7 508.3
8 886.3

El promedio se calcula en END dividiendo la suma entre el número de líneas. La suma de las cinco puntuaciones fue 343 y el promedio 68.6.

awk '{total += $3; n++} END {print total, n, total / n}' scores.txt
343 5 68.6

BEGIN sirve para mostrar una vez una línea de cabecera sobre los resultados. Sobre los artículos e importes (cantidad × precio unitario) aparece una sola vez la línea item total.

awk -F, 'BEGIN {print "item", "total"} NR > 1 {print $2, $3 * $4}' sales.csv
item total
keyboard 90
mouse 99.5
monitor 189
keyboard 45
cable 45
mouse 39.8
monitor 378

El separador de salida se cambia con la variable OFS en BEGIN. Al poner OFS como coma, donde están las comas de print entra una coma en lugar de un espacio, y la lista de cuentas sale en forma de CSV.

awk 'BEGIN {FS = ":"; OFS = ","} {print $1, $3, $7}' users.txt
root,0,/bin/bash
bin,1,/sbin/nologin
daemon,2,/sbin/nologin
nobody,65534,/sbin/nologin
user,1000,/bin/bash
deploy,1001,/bin/bash
backup,1002,/sbin/nologin

Para alinear columnas usa printf. %-10s es una cadena alineada a la izquierda en 10 posiciones, %3d es un entero de 3 posiciones y %8.2f es un número en 8 posiciones con dos decimales.

awk -F, 'NR > 1 {printf "%-10s %8.2f\n", $2, $3, $3 * $4}' sales.csv
keyboard     2    90.00
mouse        5    99.50
monitor      1   189.00
keyboard     1    45.00
cable       10    45.00
mouse        2    39.80
monitor      2   378.00

A diferencia de print, printf no cambia de línea, así que pon [\n] al final del formato. Sin [\n], los nombres de los artículos salen seguidos en una línea.

awk -F, 'NR > 1 {printf "%s ", $2}' sales.csv
keyboard mouse monitor keyboard cable mouse monitor

5️⃣ Análisis de registros y opciones del comando awk

  • ↪️ Recuento de IP de origen y códigos de estado, y resumen de opciones

🔲 Análisis de registros

Sumar a una sola variable da un solo total, así que para contar por IP de origen o por código de estado, reúne los valores en un array. n[$1]++ suma 1 a la posición del array con la IP como clave, y el for (ip in n) de END saca las posiciones una a una.

awk '{n[$1]++} END {for (ip in n) print n[ip], ip}' access.log | sort -rn
4 192.0.2.10
3 203.0.113.25
3 198.51.100.7
2 192.0.2.44

El orden en que for (ip in n) las saca no está definido (según el manual de GNU Awk), así que las ordenamos por número de solicitudes con sort -rn. 192.0.2.10 fue la que más tuvo, con 4.

Las respuestas por código de estado se cuentan igual. Hubo 3 respuestas 404 y 1 respuesta 500.

awk '{n[$9]++} END {for (s in n) print s, n[s]}' access.log | sort
200 6
301 1
304 1
404 3
500 1

Si extraes solo los códigos de estado y los pasas a sort y uniq -c, salen los mismos recuentos.

awk '{print $9}' access.log | sort | uniq -c
      6 200
      1 301
      1 304
      3 404
      1 500

Para ver solo las respuestas de error, pon una condición en el código de estado. Las líneas de 400 o más fueron tres solicitudes que buscaban wp-login.php y .env, y un error 500.

awk '$9 >= 400 {print $9, $1, $7}' access.log
404 203.0.113.25 /wp-login.php
404 203.0.113.25 /wp-login.php
404 203.0.113.25 /.env
500 198.51.100.7 /api/search?q=awk

El total de bytes enviados por IP también se calcula sumando en un array. 192.0.2.10 fue la que más recibió, con 31340 bytes.

awk '{b[$1] += $10} END {for (ip in b) print b[ip], ip}' access.log | sort -rn
31340 192.0.2.10
5120 192.0.2.44
4250 198.51.100.7
588 203.0.113.25

El campo de hora ($4) se puede comparar como cadena. Entre líneas con la misma fecha y formato, el orden de cadena coincide con el orden horario, así que seleccionamos solo las cuatro solicitudes desde las 00:05 hasta antes de las 00:10.

awk '$4 >= "[29/Oct/2026:00:05" && $4 < "[29/Oct/2026:00:10" {print $4, $7}' access.log
[29/Oct/2026:00:05:30 /contact.html
[29/Oct/2026:00:07:02 /old-page.html
[29/Oct/2026:00:07:15 /.env
[29/Oct/2026:00:09:48 /index.html

🔲 Opciones del comando awk

📌 Opciones principales: resultados de este artículo

OpciónTareaResultado en este artículo
-F fsIndica el separador de campos de entrada-F: separa el nombre de cuenta ($1) y el shell de inicio de sesión ($7) de users.txt; -F, muestra el artículo y la cantidad de sales.csv junto con la cabecera (item qty)
-v var=valAsigna un valor a una variable antes de ejecutar el programaAl pasar la variable de shell min con -v min=$min salen seis líneas con 1000 bytes enviados o más; con -v FPAT=…, la columna entre comillas de quoted.csv sale como un solo campo
-i inplaceGuarda la salida en el archivo original en lugar de la pantallaTras ejecutar gawk -i inplace, no aparece nada en pantalla y la copia de scores.txt pasa a dos columnas, nombre y puntuación; si añades -v inplace::suffix=.bak, el contenido anterior queda en un archivo .bak
--versionMuestra la información de versiónLa primera línea de [awk --version] muestra la versión GNU Awk 5

📎 Otras opciones: según el manual oficial

OpciónTarea
-f program-fileLee el programa AWK de un archivo en lugar del primer argumento de la línea de comandos; -f se puede indicar varias veces
-e program-textUsa el texto de la línea de comandos como código del programa AWK; se puede usar con funciones de biblioteca cargadas con -f o --include
-E fileParecida a -f, pero se procesa al final y bloquea las asignaciones de variables en la línea de comandos; para scripts #!
--traditionalEjecuta en modo de compatibilidad, sin reconocer las extensiones de GNU
--posixActiva el modo de compatibilidad y añade más restricciones; por ejemplo, no reconoce func, sinónimo de function
--lintAvisa de construcciones dudosas o difíciles de llevar a otras implementaciones de AWK; con --lint=fatal, los avisos pasan a ser errores fatales
--dump-variablesEscribe en un archivo una lista ordenada de las variables globales con sus tipos y valores finales; awkvars.out si no se indica archivo

🔲 Simulador del comando awk

En el simulador de abajo puedes escribir tú mismo comandos awk sobre los mismos archivos de prueba.

Simulador del comando awkGNU Awk 5
[root@server work]#
Un pequeño intérprete de awk que funciona solo en tu navegador. Los cuatro archivos de prueba son los mismos que se usaron en las mediciones, y con ↑↓ recuperas los comandos anteriores.

🔢 FAQ & contenido recomendado

El shell no cambia $min dentro de comillas simples y llega tal cual a awk, así que pásalo con la opción -v. Si pones 1000 en la variable de shell min y la pasas con -v min=$min, salen las seis líneas con 1000 bytes enviados o más. Si envuelves el programa awk en comillas dobles, el shell cambia antes incluso el $1 de [print $1] por un valor vacío, y se muestra la línea entera.

Con -i inplace, GNU Awk guarda la salida en el archivo original en lugar de la pantalla. Al ejecutar con gawk -i inplace un programa que muestra los campos primero y tercero sobre una copia de scores.txt, no apareció nada en pantalla y el archivo pasó a dos columnas, nombre y puntuación. Como sobrescribe directamente el archivo original, si añades -v inplace::suffix=.bak, el contenido anterior queda en un archivo .bak.

En el servidor AlmaLinux 9, /usr/bin/awk era un enlace simbólico a gawk, y la primera línea de [awk --version] mostraba la versión GNU Awk 5. En este servidor, los dos nombres ejecutan el mismo programa. Antes de usar funciones de GNU Awk como -i inplace o FPAT, comprueba con [awk --version] que se trata de GNU Awk.

ℹ️ Aviso de afiliados
El contenido de este sitio incluye enlaces de afiliado. Cuando un visitante compra un producto o servicio a través de uno de ellos, el sitio recibe una comisión del vendedor. El importe que paga el comprador(baja durante las promociones ↓)no aumenta. Los precios, descuentos y existencias publicados corresponden al momento de redacción y pueden variar, así que confírmalos con el vendedor antes de comprar. Los productos se eligen y evalúan con criterios propios, y las comisiones no influyen en el orden ni en el contenido de las reseñas.

Deja una respuesta

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

Demuestra que eres humano: 10   +   3   =