Introducción
Las utilidades de Linux a menudo siguen la filosofía de diseño de Unix. Se anima a que las herramientas sean pequeñas, utilicen archivos de texto plano para entrada y salida, y operen de manera modular. Debido a este legado, tenemos 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 puedes usar para manipular datos de texto de manera muy útil. En esta guía, explorarás cómo usar la herramienta de línea de comandos awk
y cómo usarla para procesar texto.
Sintaxis Básica
El comando awk
está incluido por defecto en todos los sistemas Linux modernos, así que no necesitas instalarlo para empezar a usarlo.
awk
es más útil cuando se manejan archivos de texto que están formateados de manera predecible. Por ejemplo, es excelente para analizar y manipular datos tabulares. Opera línea por línea e itera a través de todo el archivo.
Por defecto, utiliza espacios en blanco (espacios, tabulaciones, etc.) para separar los campos. Afortunadamente, muchos archivos de configuración en tu sistema Linux utilizan este formato.
El formato básico de un comando awk
es:
Puedes omitir tanto la parte de búsqueda como la parte de acción de cualquier comando awk
. Por defecto, la acción tomada si la parte de “acción” no se especifica es “print”. Esto simplemente imprime todas las líneas que coinciden.
Si la parte de búsqueda no se especifica, awk
realiza la acción indicada en cada línea.
Si ambas se especifican, awk
utiliza 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, puedes usar awk
como cat
para imprimir todas las líneas de un archivo de texto en la pantalla.
Crea un archivo favorite_food.txt
que enumere los alimentos favoritos de un grupo de amigos:
Ahora utiliza el comando awk
para imprimir el archivo en la pantalla:
Verás el archivo impreso en la pantalla:
Outputcarrot sandy
wasabi luke
sandwich brian
salad ryan
spaghetti jessica
Esto no es muy útil. Intentemos ahora las capacidades de filtrado de búsqueda de awk
buscando en el archivo el texto “sand”:
Outputcarrot sandy
sandwich brian
Como puedes ver, awk
ahora solo imprime las líneas que contienen los caracteres “sand”.
Usando expresiones regulares, puedes dirigirte a partes específicas del texto. Para mostrar solo la línea que comienza con las letras “sand”, utiliza la expresión regular ^sand
:
Esta vez, solo se muestra una línea:
Outputsandwich brian
De manera similar, puedes usar la sección de acción para especificar qué piezas de información deseas imprimir. Por ejemplo, para imprimir solo la primera columna, utiliza el siguiente comando:
Outputsandwich
Puedes hacer referencia a cada columna (delimitada por espacios en blanco) mediante variables asociadas con su número de columna. Por ejemplo, la primera columna es $1
, la segunda es $2
, y puedes referenciar toda la línea con $0
.
Variables Internas y Formato Expandido
El comando awk
utiliza algunas variables internas para asignar cierta información mientras procesa un archivo.
Las variables internas que utiliza awk
son:
- FILENAME: 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 tienes dos archivos de entrada, esto te indicaría el número de registro de cada archivo en lugar del total.
- FS: El separador de campos actual utilizado para denotar cada campo en un registro. Por defecto, está configurado como espacio en blanco.
- NF: El número de campos en el registro actual.
- NR: El número del registro actual.
- OFS: El separador de campos para los datos de salida. Por defecto, está configurado como espacio en blanco.
- ORS: El separador de registros para los datos de salida. Por defecto, 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, esto es un carácter de nueva línea.
Puedes cambiar los valores de estas variables a voluntad para que coincidan con las necesidades de tus archivos. Por lo general, haces esto durante la fase de inicialización de tu procesamiento.
Esto nos lleva a otro concepto importante. La sintaxis de awk
es ligeramente más compleja que lo que has utilizado 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 algo así:
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 puedes cambiar algunas de las variables internas en la sección BEGIN
. Por ejemplo, el archivo /etc/passwd
está delimitado con dos puntos (:
) en lugar de espacio en blanco.
Para imprimir la primera columna de este archivo, ejecuta el siguiente comando:
Outputroot
daemon
bin
sys
sync
games
man
. . .
Puedes usar los bloques BEGIN
y END
para imprimir información sobre los campos que estás imprimiendo. Usa el siguiente comando para transformar los datos del archivo en una tabla, espaciada correctamente con tabulaciones usando \t
:
Verás esta salida:
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 puedes ver, puedes formatear las cosas bastante bien aprovechando algunas de las características de awk
.
Cada una de las secciones ampliadas son opcionales. De hecho, la sección de acción principal en sí misma es opcional si se define otra sección. Por ejemplo, puedes hacer cosas como esta:
Y verás esta salida:
OutputWe can use awk like the echo command
Ahora veamos cómo buscar texto dentro de campos de la salida.
Búsqueda de Campos y Expresiones Compuestas
En uno de los ejemplos anteriores, imprimiste la línea en el archivo favorite_food.txt
que comenzaba con “sand”. Esto fue fácil porque estabas buscando al principio de toda la línea.
¿Qué pasa si quieres averiguar si un patrón de búsqueda coincide al principio de un campo en su lugar?
Crea una nueva versión del archivo favorite_food.txt
que añada un número de elemento delante de la comida de cada persona:
Si quieres encontrar todos los alimentos de este archivo que comiencen con “sa”, podrías intentar algo como esto:
Esto muestra todas las líneas que contienen “sa”:
Output1 carrot sandy
2 wasabi luke
3 sandwich brian
4 salad ryan
Aquí, estás 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 deseas. En este caso, solo estás interesado en palabras que empiecen con “sa” en la segunda columna.
Puedes indicarle a awk
que solo coincida al principio de la segunda columna usando este comando:
Como puedes ver, esto nos permite buscar solo al principio de la segunda columna para una coincidencia.
La parte field_num ~
especifica que awk
solo debe prestar atención a la segunda columna.
Output3 sandwich brian
4 salad ryan
También puedes buscar fácilmente cosas que no coincidan al incluir el carácter “!” antes del tilde (~). Este comando devolverá todas las líneas que no tengan un alimento que comience con “sa”:
Output1 carrot sandy
2 wasabi luke
5 spaghetti jessica
Si decides más adelante que solo estás interesado en las líneas que no comienzan con “sa” y el número de ítem es menor que 5, podrías usar una expresión compuesta como esta:
Esto introduce algunos conceptos nuevos. El primero es la capacidad de agregar requisitos adicionales para que la línea coincida usando el operador &&
. Usando esto, puedes combinar un número arbitrario de condiciones para que la línea coincida. En este caso, estás usando este operador para agregar una verificación de que el valor de la primera columna sea menor que 5.
Verás esta salida:
Output1 carrot sandy
2 wasabi luke
Puedes usar awk
para procesar archivos, pero también puedes trabajar con la salida de otros programas.
Procesamiento de la salida de otros programas
Puedes usar el comando awk
para analizar la salida de otros programas en lugar de especificar un nombre de archivo. Por ejemplo, puedes usar awk
para extraer la dirección IPv4 del comando ip
.
El comando ip a
muestra la dirección IP, la dirección de difusión y otra información sobre todas las interfaces de red en tu máquina. Para mostrar la información de la interfaz llamada eth0
, usa este comando:
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
Puedes usar awk
para seleccionar la línea inet
y luego imprimir solo la dirección IP:
La bandera -F
le indica a awk
que delimite por 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 delimitaste por espacios además de barras inclinadas. Ten 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ás muchos lugares donde puedes usar awk
para buscar o analizar la salida de otros comandos.
Conclusión
Para este momento, deberías tener un entendimiento básico de cómo puedes utilizar 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 incorporadas y más. Puedes usarlo dentro de tus propios scripts para formatear texto de manera confiable.
Para aprender más sobre awk
, puedes leer el libro de dominio público gratuito creado por sus creadores que entra en mucho más detalle.