AWK

 

Introducción

El nombre awk proviene de las iniciales de sus desarrolladores : Alfred V. Aho, Peter J. Weinberger y Brian W. Kerningan, de los Laboratorios Bell de AT&T. Inicialmente se desarrolló para escribir programas muy cortos, pero las características de este atrajo a los usuarios de tal modo, que lo impulsó más allá de la idea original de los autores. En 1985 apareció una nueva versión llamada nawk, en la que se implementan características nuevas como son:

awk es un lenguaje de búsqueda y procesamiento de patrones. Esto quiere decir que awk es capaz de buscar un patrón dentro de un archivo (al igual que grep) y tratarlo según unas operaciones determinadas. Con awk se pueden desarrollar auténticos programas.

Según esto awk es capaz de procesar un archivo con datos organizados por columnas y generar nuevas columnas con los valores resultantes de realizar ciertos cálculos u operaciones.

A diferencia de comandos Unix como grep y sed, que filtran y procesan texto, awk incorpora su propio lenguaje de programación, siendo capaz de ofrecer operaciones aritméticas, relaciones lógicas y variables. Se pueden desarrollar programas con awk que procesen la entrada estándar o un archivo, realizando tareas como tratar archivos de texto como bases de datos. El lenguaje de programación awk incluye estamentos como for, while e if-else, así como un conjunto de funciones y variables incorporadas.

Sintaxis:

awk [-f archivo_programa] [-Fc] ['programa'] [variable=valor ...] [archivo]

donde:

Campos y Variables

Una línea de entrada se divide en campos separados por espacios, y cada campo se denomina como $1, $2, etc. $0 indica la línea entera. Estas variables se pueden manipular (sumar, cambiar, etc.) como cualquier otra varible, por ejemplo:

awk '{ $1 = $2 + $3; print $0 }' archivo

Sumará los campos 2 y 3 en el campo 1, e imprimirá el nuevo registro (la línea completa).

Se pueden referir a los campos con expresiones numéricas como $i, $(n+1), $(NF*3/NR), etc. Si la expresión resultante no es un entera, se truncará la parte decimal. El tratamiento de un campo como texto o numérico dependerá del contexto, awk resuelve las posibles ambigüedades tratando los campos como texto (por ejemplo cuando se compara un texto con un número), por ejemplo:

x=10Asigna a x el valor numérico 10
x="Hola"Asigna a x la cadena Hola
x="2"+"2"Asigna a x el valor 4, como si se hubiera escrito x=2+2, debido a que el contexto demanda un valor numérico.

En los programas de awk no es necesario declarar las variables (indicar el tipo de variable de que se trata), se realizará automáticamente en función del contexto. Por defecto se inicializan a la cadena nula o valor numérico 0, por lo que no es necesario inicializarlas, aunque es recomendable para facilitar la legibilidad del programa declararlas e inicializarlas.

Existen unas variables predefinidas, que pueden ser utiles dentro del programa (no llevan el $ delante) y son:

Los valores de las variables relativas a separadores se pueden modificar en cualquier momento, asignándole el valor de cualquier carácter. Por defecto, los separadores de campos son espacios, y los de registros el carácter nueva línea.

Formato de los estamentos

La estructura general de los estamentos o conjuntos patrón-acción es:

Patrón  { acción }

Interpretación:

Si no se especifica la acción, se mostrarán por pantalla aquellas líneas que contengan el patrón. La acción está formada por estamentos (if, for, print, sprintf, next), los cuales deben finalizar en ";", Nueva Línea o llaves. Dentro de las acciones se pueden realizar operaciones matemáticas, de concatenación, etc. Las variables utilizadas pueden ser escalares, campos o tablas, y son inicializadas a la cadena nula.

Los patrones deben ir rodeados por caracteres "/", y puede contener dos patrones separados por una coma, en cuyo caso la acción se realizará para aquellas líneas comprendidas entre la primera aparición del primer patrón y la siguiente aparición del segundo patrón. Si se utiliza el símbolo "~", indicará que el patrón de la derecha está contenido en el campo de la izquierda, y si se utiliza "!~", indicará que no está contenido.

Existen dos etiquetas opcionales, con un significado especial, que hacen que un programa awk tenga una estructura como la siguiente:

BEGIN  { acción }
Patrón  { acción }
END  { acción }

La acción indicada en la etiqueta BEGIN se ejecutará antes de leer cualquier entrada, mientras que la acción asociada a la etiqueta END se ejecutará una vez tratadas todas las entradas. La etiqueta END se puede utilizar para imprimir resultados totales, o cálculos realizados con todos los registros leídos.

Cuando el conjunto patrón-acción se introduce desde la línea de comandos, es necesario que vaya encerrado entre comillas simples, para protegerlo de la shell. Por ejemplo:

Desde un archivoDesde la shell de Unix
length > 60awk 'length > 60'

A continuación se muestran los diferentes tipos de acciones y estamentos.

if (expresión) estamento [else estamento]  
while (expresión) estamento  
for (inicialización ; final ; incremento) estamento  
for (var in array) estamento  
do estamento while (expresión)  
break  
continue  
{ [estamento] }  
expresión por ejemplo una asignacion var=valor
print [lista de expresiones] [ > expresión]  
printf formato[, lista de expresiones] [ > expresión]  
return [expresión]  
next salta los elementos restantes de la línea de entrada
delete array [expresión] Borra un elemento array
exit [expresión] Finaliza la ejecución del programa, devolviendo el valor indicado en expresión.

Operaciones

Un programa awk puede hacer operaciones en coma flotante, utilizando los siguientes operadores:

+, -, *, / Adición, sustración, multiplicación y división
% Operador módulo o resto.
++, -- Operador de incremente y decremento
+=, -=, *=, /=, %= Asinación al estilo C (x += 1 equivale a x = x + 1)

Funciones Incorporadas

Las siguientes funciones se pueden utilizar para la realización de operaciones aritméticas y con cadenas de caracteres.

FunciónDescripción
length(x) Devuelve la longitud del argumento
sqrt(x) Devuelve la raíz cuadrada del argumento
log(x) Devuelve el logaritmo en neperiano del argumento (en base e)
exp(x) Devuelve el valor de e elevado al argumento
int(x)Devuelve la parte entera del argumento
cos(x) Devuelve el coseno del argumento
sin(x) Devuelve el seno del argumento
atan(x) Devuelve el arcotangente del argumento
rand() Devuelve un número aleatorio comprendido entre 0 y 1
match(s,r) Devuelve la posición de s en donde ocurre r, comenzando desde 1. Si no existe devuelve 0.
substr(s,m,n) Devuelve la subcadena de s que comienza en la posición m y finaliza en la n.
sub(r,t,s) Sustituye la primera ocurrencia de t por r en la cadena s. Si no se especifica s se tomará todo el registro ($0).
gsub(r,t,s) Igual que sub, pero sustituyendo todas las ocurrencias.
split(s,array,sep) Divide la cadena s en array[1],...,array[n]. Se devuelve el número de elementos. Si no se especifica el separador en sep se utilizará el valor de FS. s puede ser una variable.
index(s1,s2) Devuelve la posición de la cadena s1 en donde se encuentra la cadena s2. En caso de no encontrarse se devuelve 0.
sprintf(f,e1,e2,...) Devuelve la cadena resultante de imprimir los valores e1, e2, ... con el formato especificado en f.
toupper(s) Devuelve la cadena s convertida a mayúsculas.
tolower(s) Devuelve la cadena s convertida a minúsculas.
system(cmd) Ejecuta el comando UNIX cmd especificado y retorna el estado de salida de este.
print e1, e2, ... Presenta en la salida los valores e1, e2, ...
printf f, e1, e2, ... Presenta en la salida los valores e1, e2, ... con el formato especificado por f (al estilo C: %s, %d, etc.).
close(f) Cierra el archivo o pipe abierto con print, printf o getline.
getline X Lee el siguiente registro de la entrada y se lo asigna a X, si no se especifica X se asignará a $0.

La concatenación de cadenas no tiene ningua función ni operación especial, simplemente se realiza escribiendo expresiones tras otras:

Persona = Apellidos ", " Nombre

Funciones

Las funciones se pueden definir (en la posición de un estamentopatrón-acción) del siguiente modo:

function Nombre_Funcion(p1, p2, p3)
{
 ...
return x
}

Los parámetros se pasan por valor si son escalares y por referencia si se pasa el nombre del array. Los parámetros son locales, mientras que el resto de las variables son globales. Las funciones pueden llamarse de forma recursiva.

Ejemplos

Ejemplos de patrones

/prueba/ Todas las líneas que contengan la cadena "prueba".
$2 ~ /prueba/ Todas las líneas cuyo segundo campo contenga la cadena "prueba".
$1 !~ /prueba/ Todas las líneas cuyo primer campo no contenga la cadena "prueba".
/start/ , /stop/ Todas las líneas existentes entre los patrones "start" y "stop".

Ejemplos de acciones

{ print $5 } Imprime el campo 5.
{ print $1 $3 } Imprime los campos 1 y 3 consecutivamente.
{ s=$2+$3 ; print  s } Suma los campos 2 y 3 e imprime el resultado.
{tot=$2+$3; print $0, tot} Suma de los campos 2 y 3, e imprime la línea original y la suma.
BEGIN {FS = ",[ \t]*|[ \t]+" }
{ s += $1; print $2, $1 }
END { print "La suma es ", s , "La media es ", s/NR
Toma como separador de entrada la coma y/o los blancos y tabulaciones.
Suma el primer campo de todos los registros e imprime los campos 2 y 1 (en ese orden).
Al final imprime el total y la media.

Ejemplos

ls -l | awk '/txt/ { print &8 }' - Muestra los archivos que contengan como propietario, nombre, grupo, etc. la cadena txt. El símbolo "-" indica que el archivo es la entrada estándar. 
awk '/cadena/ { cont=cont+$2 ; print $2 "\t" cont }' cont=0 archivo Busca cadena en archivo y en una variable llamada cont (contador) va sumando los valores del campo 2 e imprimiendo dicho campo, un tabulador y el valor del contador. Al final de la salida tendremos la suma total de los valores que ha tenido cadena en el campo 2.
awk '$2>0 { print $1," ", $2 }' archivo Para cada línea de archivo, si el 2º campo es positivo, imprime los dos primeros campos.
awk '$2>0 { printf "%s %d\n", $1, $2 }' archivo Idem que el caso anterior, suponiendo que el primer campo es una cadena de caracteres.
awk '{gsub(" ","",$0); print $0;}' archivo Elimina todos los espacios en blanco del archivo especificado y lo muestra en pantalla.
awk '{if (NF>0) print $0}' archivo Elimina todas las líneas vacías de archivo
awk '{} END {print NR}' archivo Muestra el número de registros (líneas) que contiene archivo

El siguiente ejemplo suma las columnas 2, 3 y 4 de un archivo, presentando el resultado al final.

cat archivo | awk '
	BEGIN { campo1=0; campo2=0; campo3=0; }
	{
	campo1+=$2;
	campo2+=$3;
	campo3+=$4;
	}
	END { printf "campo1 = %d\t campo2 = %d\t campo3 = %d\n", campo1, campo2, campo3; }'

En el siguiente ejemplo se hace lo mismo que en el anterior pero para las lineas que contengan la palabra TOTAL en el primer campo.

cat archivo | awk 'BEGIN { campo1=0; campo2=0; campo3=0; } $1 ~ /TOTAL/ {
	campo1+=$2;
	campo2+=$3;
	campo3+=$4;
	}
	END { printf "campo1 = %d\t campo2 = %d\t campo3 = %d\n", campo1, campo2, campo3; }'