Cómo usar el lenguaje AWK para manipular texto en Linux
Introducción
Las utilidades de Linux a menudo siguen la filosofía de diseño de Unix. Se recomienda que las herramientas sean pequeñas, utilicen archivos de texto sin formato para la entrada y la salida y funcionen de forma modular. Debido a este legado, contamos con una gran funcionalidad de procesamiento de texto con herramientas como sed y awk
.
awk
es tanto un lenguaje de programación como un procesador de texto que puede usar para manipular datos de texto de formas muy útiles. En esta guía, explorará cómo usar la herramienta de línea de comando awk
y cómo usarla para procesar texto.
Sintaxis básica
El comando awk
se incluye de forma predeterminada en todos los sistemas Linux modernos, por lo que no necesita instalarlo para comenzar a usarlo.
awk
es más útil cuando se manejan archivos de texto que tienen un formato predecible. Por ejemplo, es excelente para analizar y manipular datos tabulares. Funciona línea por línea y recorre todo el archivo.
De forma predeterminada, utiliza espacios en blanco (espacios, tabulaciones, etc.) para separar los campos. Afortunadamente, muchos archivos de configuración en su sistema Linux usan este formato.
El formato básico de un comando awk
es:
- awk '/search_pattern/ { action_to_take_on_matches; another_action; }' file_to_parse
Puede omitir la parte de búsqueda o la parte de acción de cualquier comando awk
. De forma predeterminada, la acción que se realiza si no se proporciona la parte \acción es \imprimir. Esto simplemente imprime todas las líneas que coinciden.
Si no se proporciona la parte de búsqueda, awk
realiza la acción enumerada en cada línea.
Si se dan ambos, awk
usa la parte de búsqueda para decidir si la línea actual refleja el patrón y luego realiza las acciones en las coincidencias.
En su forma más simple, puede usar awk
como cat
para imprimir todas las líneas de un archivo de texto en la pantalla.
Cree un archivo favorite_food.txt
que enumere las comidas favoritas de un grupo de amigos:
- echo "carrot sandy
- wasabi luke
- sandwich brian
- salad ryan
- spaghetti jessica" > favorite_food.txt
Ahora use el comando awk
para imprimir el archivo en la pantalla:
- awk '{print}' favorite_food.txt
Verá el archivo impreso en la pantalla:
Outputcarrot sandy
wasabi luke
sandwich brian
salad ryan
spaghetti jessica
Esto no es muy útil. Probemos las capacidades de filtrado de búsqueda de awk
buscando en el archivo el texto \arena:
- awk '/sand/' favorite_food.txt
Outputcarrot sandy
sandwich brian
Como puede ver, awk
ahora solo imprime las líneas que tienen los caracteres \arena en ellas.
Usando expresiones regulares, puede apuntar a partes específicas del texto. Para mostrar solo la línea que comienza con las letras \arena, use la expresión regular ^sand
:
- awk '/^sand/' favorite_food.txt
Esta vez, solo se muestra una línea:
Outputsandwich brian
De manera similar, puede usar la sección de acción para especificar qué información desea imprimir. Por ejemplo, para imprimir solo la primera columna, use el siguiente comando:
- awk '/^sand/ {print $1;}' favorite_food.txt
Outputsandwich
Puede hacer referencia a cada columna (según lo delimitado por espacios en blanco) por variables asociadas con su número de columna. Por ejemplo, la primera columna es $1
, la segunda es $2
y puede hacer referencia a toda la línea con $0
.
Variables Internas y Formato Expandido
El comando awk
usa algunas variables internas para asignar cierta información mientras procesa un archivo.
Las variables internas que usa awk
son:
- NOMBRE DE ARCHIVO: hace referencia al archivo de entrada actual.
- FNR: hace referencia al número del registro actual en relación con el archivo de entrada actual. Por ejemplo, si tiene dos archivos de entrada, esto le indicará el número de registro de cada archivo en lugar del total.
- FS: el separador de campo actual utilizado para indicar cada campo en un registro. De forma predeterminada, se establece en espacios en blanco.
- NF: El número de campos en el registro actual.
- NR: El número del registro actual.
- OFS: el separador de campo para los datos de salida. De forma predeterminada, se establece en espacios en blanco.
- ORS: el separador de registros para los datos de salida. De forma predeterminada, este es un carácter de nueva línea.
- RS: el separador de registros utilizado para distinguir registros separados en el archivo de entrada. De forma predeterminada, este es un carácter de nueva línea.
Puede cambiar los valores de estas variables a voluntad para que coincidan con las necesidades de sus archivos. Por lo general, hace esto durante la fase de inicialización de su procesamiento.
Esto nos lleva a otro concepto importante. La sintaxis awk
es un poco más compleja que la que has usado hasta ahora. También hay bloques opcionales BEGIN
y END
que pueden contener comandos para ejecutar antes y después del procesamiento del archivo, respectivamente.
Esto hace que nuestra sintaxis expandida se vea así:
- awk 'BEGIN { action; }
- /search/ { action; }
- END { action; }' input_file
Las palabras clave BEGIN
y END
son conjuntos específicos de condiciones, al igual que los parámetros de búsqueda. Coinciden antes y después de que se haya procesado el documento.
Esto significa que puede cambiar algunas de las variables internas en la sección BEGIN
. Por ejemplo, el archivo /etc/passwd
está delimitado por dos puntos (:
) en lugar de espacios en blanco.
Para imprimir la primera columna de este archivo, ejecute el siguiente comando:
- awk 'BEGIN { FS=":"; }
- { print $1; }' /etc/passwd
Outputroot
daemon
bin
sys
sync
games
man
. . .
Puede utilizar los bloques BEGIN
y END
para imprimir información sobre los campos que está imprimiendo. Use el siguiente comando para transformar los datos del archivo en una tabla, bien espaciados con pestañas usando
:
- awk 'BEGIN { FS=":"; print "User\t\tUID\t\tGID\t\tHome\t\tShell\n--------------"; }
- {print $1,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}
- END { print "---------\nFile Complete" }' /etc/passwd
Verás este resultado:
OutputUser UID GID Home Shell
--------------
root 0 0 /root /bin/bash
daemon 1 1 /usr/sbin /bin/sh
bin 2 2 /bin /bin/sh
sys 3 3 /dev /bin/sh
sync 4 65534 /bin /bin/sync
. . .
---------
File Complete
Como puede ver, puede formatear las cosas bastante bien aprovechando algunas de las características de awk
.
Cada una de las secciones ampliadas es opcional. De hecho, la propia sección de acción principal es opcional si se define otra sección. Por ejemplo, puedes hacer cosas como esta:
- awk 'BEGIN { print "We can use awk like the echo command"; }'
Y verás este resultado:
OutputWe can use awk like the echo command
Ahora veamos cómo buscar texto dentro de los campos de la salida.
Búsqueda de campos y expresiones compuestas
En uno de los ejemplos anteriores, imprimió la línea en el archivo favorite_food.txt
que comenzaba con \sand. Esto fue fácil porque estaba buscando el comienzo de toda la línea.
¿Qué pasaría si quisiera averiguar si un patrón de búsqueda coincide con el comienzo de un campo?
Cree una nueva versión del archivo favorite_food.txt
que agrega un número de artículo delante de la comida de cada persona:
- echo "1 carrot sandy
- 2 wasabi luke
- 3 sandwich brian
- 4 salad ryan
- 5 spaghetti jessica" > favorite_food.txt
Si desea encontrar todos los alimentos de este archivo que comienzan con \sa, puede comenzar probando algo como esto:
- awk '/sa/' favorite_food.txt
Esto muestra todas las líneas que contienen \sa”:
Output1 carrot sandy
2 wasabi luke
3 sandwich brian
4 salad ryan
Aquí, está haciendo coincidir cualquier instancia de \sa” en la palabra. Esto termina incluyendo cosas como \wasabi”, que tiene el patrón en el medio, o \sandy”, que no está en la columna que desea. En este caso de que solo le interesen las palabras que comienzan con \sa” en la segunda columna.
Puedes decirle a awk
que solo coincida al comienzo de la segunda columna usando este comando:
- awk '$2 ~ /^sa/' favorite_food.txt
Como puede ver, esto nos permite buscar solo al comienzo de la segunda columna una coincidencia.
La parte field_num ~
especifica que awk
solo debe prestar atención a la segunda columna.
Output3 sandwich brian
4 salad ryan
Puede buscar con la misma facilidad cosas que no coinciden incluyendo \!” carácter antes de la tilde (~). Este comando devolverá todas las líneas que no tienen una comida que comienza con \sa”:
- awk '$2 !~ /^sa/' favorite_food.txt
Output1 carrot sandy
2 wasabi luke
5 spaghetti jessica
Si luego decide que solo le interesan las líneas que no comienzan con \sa y el número de artículo es menor que 5, puede usar una expresión compuesta como esta:
- awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt
Esto introduce algunos conceptos nuevos. La primera es la capacidad de agregar requisitos adicionales para que la línea coincida mediante el uso del operador &&
. Con esto, puede combinar un número arbitrario de condiciones para que la línea coincida. En este caso, está utilizando este operador para agregar una verificación de que el valor de la primera columna es menor que 5.
Verás este resultado:
Output1 carrot sandy
2 wasabi luke
Puede usar awk
para procesar archivos, pero también puede trabajar con la salida de otros programas.
Salida de procesamiento de otros programas
Puede usar el comando awk
para analizar la salida de otros programas en lugar de especificar un nombre de archivo. Por ejemplo, puede usar awk
para analizar la dirección IPv4 desde el comando ip
.
El comando ip a
muestra la dirección IP, la dirección de transmisión y otra información sobre todas las interfaces de red en su máquina. Para mostrar la información de la interfaz llamada eth0
, use este comando:
- ip a s eth0
Verás los siguientes resultados:
Output2571: eth0@if2572: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:0b brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.11/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
Puede usar awk
para apuntar a la línea inet
y luego imprimir solo la dirección IP:
- ip a s eth0 | awk -F '[\/ ]+' '/inet / {print $3}'
El indicador -F
le dice a awk
que delimite con barras inclinadas o espacios usando la expresión regular [\/ ]+
. Esto divide la línea inet 172.17.0.11/16
en campos separados. La dirección IP está en el tercer campo porque los espacios al principio de la línea también cuentan como un campo, ya que los delimitaste tanto con espacios como con barras. Tenga en cuenta que awk
trató los espacios consecutivos como un solo espacio en este caso.
La salida muestra la dirección IP:
Output172.17.0.11
Encontrará muchos lugares donde puede usar awk
para buscar o analizar la salida de otros comandos.
Conclusión
A estas alturas, debería tener una comprensión básica de cómo puede usar el comando awk
para manipular, formatear e imprimir selectivamente archivos de texto y flujos de texto. Sin embargo, Awk es un tema mucho más amplio y, en realidad, es un lenguaje de programación completo con asignación de variables, estructuras de control, funciones integradas y más. Puede usarlo dentro de sus propios scripts para dar formato al texto de manera confiable.
Para obtener más información sobre awk
, puede leer el libro gratuito de dominio público de sus creadores, que contiene muchos más detalles.