Introducción
El nombre awk proviene de las iniciales de sus desarrolladores : Alfred V. Aho, Brian W. Kerningan y Peter J. Weinberger, 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:
• Funciones de usuario.
• Expresiones regulares dinámicas con sustitución de texto.
• Mayor número de funciones intrínsecas y variables.
• Nuevos operadores y estamentos.
• Entrada de múltiples archivos.
• Acceso a argumentos en la línea de comandos.
• Mejora de los mensajes de error.
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.
La sintaxis de awk es:
awk [-f archivo_programa] [-Fc] ['programa'] [variable=valor ...] [archivo]
donde:
archivo_programa : especifica el archivo fuente del programa a aplicar a archivo.
c : especifica el carácter delimitador de campos. Por defecto se considera el espacio en blanco.
programa : especifica el conjunto de patrones e instrucciones a ejecutar con archivo. La diferencia con archivo_programa, es que en este caso hay que especificar los patrones e instrucciones en la línea de comandos. Para evitar interferencias con la shell deben ir encerradas entre comillas simples (').
variable=valor : se utiliza para establecer los valores que tomarán las variables que utilice el programa.
archivo : archivo que será procesado por awk. Si se especifica "-" se interpretará como la entrada estándar.
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=10 Asigna 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.
Existen unas variables predefinidas, que pueden ser utilizadas dentro del programa:
•FS : Separador del campo de entrada. Se puede especificar con la opción -Fc en la línea de comandos
•FILENAME : nombre del archivo de entrada actual
•RS : Separador de registro de entrada
•OFS : Separador del campo de salida.
•ORS : Separador de registro de salida
•NF : Número de campos en el registro actual
•NR : Número de registros procesados hasta el momento. Al final del programa se podrá conocer el número e registros tratados.
•RSTART : Posición de la cadena en la que se verifica el patrón utilizado, comenzando desde 1. Es equivalente al valor retornado por la función match.
•RLENGTH : Longitud de la cadena en la que se verifica el patrón utilizado.
•SUBSEP : Separador de cadenas en arrays multidimensionales. El valor por defecto es " 34".
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:
•Para cada línea que verifique lo especificado en el patrón, se ejecutará la acción indicada.
•La acción siempre va encerrada entre llaves.
•Se pueden especificar varias acciones, separándolas por ";" o por el carácter nueva línea.
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, se recomienda que vaya encerrado entre comillas simples, para protegerlo de la shell.
Por ejemplo:
Desde un archivo Desde la shell de Unix
length > 60 awk '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)
O : exp.1 exp2 verdadera si es cualquiera de las dos ; exp. 2 no se evalua si expr1 es verdadera
&& Y : exp1 && exp2 verdadera si ambas lo son , expr2 no se avalúa si expr1 es falsa
> >= < <= == != Operaciones relacionales Nothing Concatenacion de cadenas Funciones Incorporadas Las siguientes funciones se pueden utilizar para la realización de operaciones aritméticas y con cadenas de caracteres. Función Descripció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. Funciones Las funciones se pueden definir (en la posición de un estamentopatrón-acción) del siguiente modo: function Nombre_Función(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/ Imprime 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.