Awk es una de las herramientas más antiguas en la caja de herramientas del usuario de Unix y Linux. Creado en la década de 1970 por Alfred Aho, Peter Weinberger y Brian Kernighan (las A, W y K del nombre de la herramienta), awk se creó para el procesamiento complejo de flujos de texto. Es una herramienta complementaria de sed, el editor de secuencias, que está diseñado para el procesamiento de archivos de texto línea por línea. Awk permite programas estructurados más complejos y es un lenguaje de programación completo.
Este artículo explicará cómo usar awk para tareas más estructuradas y complejas, incluida una aplicación simple de combinación de correspondencia.
Estructura del programa Awk
Un script awk se compone de bloques funcionales rodeados de {} (corchetes). Hay dos bloques de funciones especiales, BEGIN y FIN , que se ejecutan antes de procesar la primera línea del flujo de entrada y después de procesar la última línea. En el medio, los bloques tienen el formato:
pattern { action statements }
Cada bloque se ejecuta cuando la línea en el búfer de entrada coincide con el patrón. Si no se incluye ningún patrón, el bloque de funciones se ejecuta en cada línea del flujo de entrada.
Además, la siguiente sintaxis se puede usar para definir funciones en awk que se pueden llamar desde cualquier bloque:
function name(parameter list) { statements }
Esta combinación de bloques y funciones de coincidencia de patrones permite al desarrollador estructurar programas awk para su reutilización y legibilidad.
Cómo procesa awk los flujos de texto
Awk lee el texto de su archivo de entrada o transmite una línea a la vez y usa un separador de campo para analizarlo en varios campos. En terminología awk, el búfer actual es un registro . Hay una serie de variables especiales que afectan la forma en que awk lee y procesa un archivo:
- FS (separador de campo):por defecto, este es cualquier espacio en blanco (espacios o tabulaciones)
- RS (separador de registro):De forma predeterminada, una nueva línea (\n )
- NF (número de campos):cuando awk analiza una línea, esta variable se establece en el número de campos que se han analizado
- $0: El registro actual
- $1, $2, $3, etc.: El primer, segundo, tercer campo, etc. del registro actual
- NR (número de registros):el número de registros que el script awk ha analizado hasta ahora
Hay muchas otras variables que afectan el comportamiento de awk, pero esto es suficiente para empezar.
Awk one-liners
Para una herramienta tan poderosa, es interesante que la mayor parte del uso de awk sean frases sencillas. Quizás el programa awk más común imprime los campos seleccionados desde una línea de entrada de un archivo CSV, un archivo de registro, etc. Por ejemplo, el siguiente renglón imprime una lista de nombres de usuario de /etc/passwd :
awk -F":" '{print $1 }' /etc/passwd
Como se mencionó anteriormente, $1 es el primer campo en el registro actual. La -F La opción establece la variable FS en el carácter : .
El separador de campo también se puede establecer en un bloque de funciones BEGIN:
awk 'BEGIN { FS=":" } {print $1 }' /etc/passwd
En el siguiente ejemplo, cada usuario cuyo shell no sea /sbin/nologin se puede imprimir precediendo al bloque con una coincidencia de patrón:
awk 'BEGIN { FS=":" } ! /\/sbin\/nologin/ {print $1 }' /etc/passwd
Awk avanzado:Combinar correspondencia
Ahora que tiene algunos de los conceptos básicos, intente profundizar en awk con un ejemplo más estructurado:crear una combinación de correspondencia.
Una combinación de correspondencia utiliza dos archivos, uno (llamado en este ejemplo email_template.txt ) que contiene una plantilla para un correo electrónico que desea enviar:
From: Program committee <[email protected]>
To: {firstname} {lastname} <{email}>
Subject: Your presentation proposal
Dear {firstname},
Thank you for your presentation proposal:
{title}
We are pleased to inform you that your proposal has been successful! We
will contact you shortly with further information about the event
schedule.
Thank you,
The Program Committee
Y el otro es un archivo CSV (llamado proposals.csv ) con las personas a las que desea enviar el correo electrónico:
firstname,lastname,email,title
Harry,Potter,[email protected],"Defeating your nemesis in 3 easy steps"
Jack,Reacher,[email protected],"Hand-to-hand combat for beginners"
Mickey,Mouse,[email protected],"Surviving public speaking with a squeaky voice"
Santa,Claus,[email protected],"Efficient list-making"
Desea leer el archivo CSV, reemplazar los campos relevantes en el primer archivo (saltando la primera línea), luego escribir el resultado en un archivo llamado acceptanceN.txt , incrementando N por cada línea que analices.
Escriba el programa awk en un archivo llamado mail_merge.awk . Las declaraciones están separadas por ; en scripts awk. La primera tarea es establecer la variable separadora de campo y un par de otras variables que necesita el script. También debe leer y descartar la primera línea en el CSV, o se creará un archivo que comenzará con Estimado nombre . Para hacer esto, use la función especial getline y restablecer el contador de registros a 0 después de leerlo.
BEGIN {
FS=",";
template="email_template.txt";
output="acceptance";
getline;
NR=0;
}
La función principal es muy sencilla:para cada línea procesada, se establece una variable para los distintos campos:firstname , apellido , correo electrónico y título . El archivo de plantilla se lee línea por línea y la función sub se utiliza para sustituir cualquier ocurrencia de las secuencias de caracteres especiales con el valor de la variable relevante. Luego, la línea, con las sustituciones realizadas, se envía al archivo de salida.
Dado que está tratando con el archivo de plantilla y un archivo de salida diferente para cada línea, debe limpiar y cerrar los identificadores de archivo para estos archivos antes de procesar el siguiente registro.
{
# Read relevant fields from input file
firstname=$1;
lastname=$2;
email=$3;
title=$4;
# Set output filename
outfile=(output NR ".txt");
# Read a line from template, replace special fields, and
# print result to output file
while ( (getline ln < template) > 0 )
{
sub(/{firstname}/,firstname,ln);
sub(/{lastname}/,lastname,ln);
sub(/{email}/,email,ln);
sub(/{title}/,title,ln);
print(ln) > outfile;
}
# Close template and output file in advance of next record
close(outfile);
close(template);
}
¡Ya terminaste! Ejecute el script en la línea de comando con:
awk -f mail_merge.awk proposals.csv
o
awk -f mail_merge.awk < proposals.csv
y encontrará archivos de texto generados en el directorio actual.
Awk avanzado:recuento de frecuencia de palabras
Una de las características más poderosas de awk es la matriz asociativa. En la mayoría de los lenguajes de programación, las entradas de la matriz generalmente se indexan mediante un número, pero en awk, las matrices se referencian mediante una cadena clave. Puede almacenar una entrada del archivo proposals.txt de la sección anterior. Por ejemplo, en una sola matriz asociativa, como esta:
proposer["firstname"]=$1;
proposer["lastname"]=$2;
proposer["email"]=$3;
proposer["title"]=$4;
Esto hace que el procesamiento de texto sea muy fácil. Un programa simple que utiliza este concepto es la idea de un contador de frecuencia de palabras. Puede analizar un archivo, dividir palabras (ignorando la puntuación) en cada línea, incrementar el contador para cada palabra en la línea y luego generar las 20 palabras principales que aparecen en el texto.
Primero, en un archivo llamado wordcount.awk , establezca el separador de campo en una expresión regular que incluya espacios en blanco y puntuación:
BEGIN {
# ignore 1 or more consecutive occurrences of the characters
# in the character group below
FS="[ .,:;()<>{}@!\"'\t]+";
}
A continuación, la función de bucle principal iterará sobre cada campo, ignorando los campos vacíos (lo que sucede si hay puntuación al final de una línea), e incrementará el recuento de palabras para las palabras en la línea.
{
for (i = 1; i <= NF; i++) {
if ($i != "") {
words[$i]++;
}
}
}
Finalmente, después de procesar el texto, use la función END para imprimir el contenido de la matriz, luego use la capacidad de awk para canalizar la salida a un comando de shell para hacer una ordenación numérica e imprimir las 20 palabras más frecuentes:
END {
sort_head = "sort -k2 -nr | head -n 20";
for (word in words) {
printf "%s\t%d\n", word, words[word] | sort_head;
}
close (sort_head);
}
Ejecutar este script en un borrador anterior de este artículo produjo este resultado:
[[email protected]]$ awk -f wordcount.awk < awk_article.txt
the 79
awk 41
a 39
and 33
of 32
in 27
to 26
is 25
line 23
for 23
will 22
file 21
we 16
We 15
with 12
which 12
by 12
this 11
output 11
function 11
¿Qué sigue?
Más recursos de Linux
- Hoja de trucos de los comandos de Linux
- Hoja de trucos de comandos avanzados de Linux
- Curso en línea gratuito:Descripción general técnica de RHEL
- Hoja de trucos de red de Linux
- Hoja de trucos de SELinux
- Hoja de trucos de los comandos comunes de Linux
- ¿Qué son los contenedores de Linux?
- Nuestros últimos artículos sobre Linux
Si desea obtener más información sobre la programación awk, le recomiendo encarecidamente el libro Sed and awk por Dale Dougherty y Arnold Robbins.
Una de las claves para progresar en la programación awk es dominar las "expresiones regulares extendidas". Awk ofrece varias adiciones poderosas a la sintaxis de expresiones regulares sed con las que quizás ya esté familiarizado.
Otro gran recurso para aprender awk es la guía del usuario de GNU awk. Tiene una referencia completa para la biblioteca de funciones integrada de awk, así como muchos ejemplos de scripts de awk simples y complejos.