Búsqueda de sitios web

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:

  1. 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:

  1. echo "carrot sandy
  2. wasabi luke
  3. sandwich brian
  4. salad ryan
  5. spaghetti jessica" > favorite_food.txt

Ahora use el comando awk para imprimir el archivo en la pantalla:

  1. awk '{print}' favorite_food.txt

Verá el archivo impreso en la pantalla:

Output
carrot 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:

  1. awk '/sand/' favorite_food.txt
Output
carrot 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:

  1. awk '/^sand/' favorite_food.txt

Esta vez, solo se muestra una línea:

Output
sandwich 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:

  1. awk '/^sand/ {print $1;}' favorite_food.txt
Output
sandwich

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í:

  1. awk 'BEGIN { action; }
  2. /search/ { action; }
  3. 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:

  1. awk 'BEGIN { FS=":"; }
  2. { print $1; }' /etc/passwd
Output
root 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 :

  1. awk 'BEGIN { FS=":"; print "User\t\tUID\t\tGID\t\tHome\t\tShell\n--------------"; }
  2. {print $1,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}
  3. END { print "---------\nFile Complete" }' /etc/passwd

Verás este resultado:

Output
User 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:

  1. awk 'BEGIN { print "We can use awk like the echo command"; }'

Y verás este resultado:

Output
We 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:

  1. echo "1 carrot sandy
  2. 2 wasabi luke
  3. 3 sandwich brian
  4. 4 salad ryan
  5. 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:

  1. awk '/sa/' favorite_food.txt

Esto muestra todas las líneas que contienen \sa”:

Output
1 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:

  1. 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.

Output
3 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”:

  1. awk '$2 !~ /^sa/' favorite_food.txt
Output
1 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:

  1. 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:

Output
1 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:

  1. ip a s eth0

Verás los siguientes resultados:

Output
2571: 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:

  1. 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:

Output
172.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.