La función básica de awk es buscar líneas en ficheros
(u otras unidades de texto) que contienen ciertos patrones. Cuando en una línea
se encuentra un patrón, awk realiza las acciones especificadas para dicho patrón
sobre dicha línea. Awk sigue realizando el procesamiento de las líneas de entrada de esta forma
hasta que se llega al final del fichero.
Cuando ejecutas awk, especificas un programa awk que le dice a awk que tiene que hacer. El programa consiste en una serie
de reglas (podría también contener definiciones de funciones, pero esa
es una característica avanzada, así que ignorémosla por ahora. Ver la sección
11. Funciones definidas
por el Usuario). Cada regla especifica
un patrón a buscar, y una acción a realizar cuando se encuentre dicho patrón
en el registro de entrada.
Sintácticamente, una regla consiste en un patrón seguido por
una acción. La acción se encierra entre llaves para separarlas de los patrones.
Las reglas están separadas por caracteres newline. Por lo tanto, un programa
awk presentaría la siguiente forma:
patrón { acción }
patrón { acción }
...
El siguiente comando ejecuta un programa awk simple que busca la cadena de caracteres foo en el fichero de entrada
ListaBBS y si la encuentra la imprime. (Las cadenas de caracteres son normalmente
llamadas cadenas. )
awk '/foo/ { print $0 }' ListaBBS
Cuando se encuentran líneas que contengan foo, éstas son impresas,
ya que print $0 hace que se imprima la línea actual.
Habrás advertido las barras, /, alrededor de la cadena foo
en el programa awk. Las barras indican que foo es un patrón para búsqueda. Este tipo de
patrón se llama expresión regular, y es cubierta con más detalle posteriormente
(Ver la sección Expresiones
Regulares como Patrones). Existen comillas simples
alrededor del programa awk para que el shell no interprete el programa como caracteres
especiales de la shell.
Aquí se muestra lo que este programa imprime:
fooey 5551234 2400/1200/300 B
foot 5556699 1200/300 B
macfoo 5556480 1200/300 A
sabafoo 5552127 1200/300 C
En una regla awk, o el patrón o la acción puede ser omitida, pero no ambos. Si el patrón
se omite, entonces la acción se realiza para cada línea de entrada. Si se omite
la acción, la acción por defecto es imprimir todas las líneas que concuerden
con el patrón.
Por lo que, podríamos omitir la acción (la sentencia print y
las llaves) en el ejemplo anterior, y el resultado sería el mismo: todas las
líneas que concuerden con el patrón foo serán impresas. Por comparación, la
omisión de la sentencia print pero manteniendo las llaves produce una acción
vacía que no realiza nada; por lo que no se imprimirá ninguna línea.
La utilidad awk lee los ficheros de entrada línea a línea. Para cada
línea, awk comprueba todos los patrones de todas las reglas. Si concuerdan varios
patrones entonces se ejecutan las distintas acciones de cada patrón, en el orden
en que aparecen en el programa awk. Si no concuerda ningún patrón, entonces no se ejecuta
ninguna acción.
Después de ejecutar las acciones de las reglas que
concuerden con la línea (quizás no concuerde ninguna), awk lee la siguiente línea (aunque existen excepciones,
Ver la sección La Sentencia next).
Esto continúa hasta que se alcanza el final de fichero.
Por ejemplo, el programa awk:
/12/ { print $0 }
/21/ { print $0 }
contiene dos reglas. La primera regla tiene la cadena 12 como patrón y realiza la acción print $0. La segunda regla tiene la cadena 21 como patrón y también realiza la acción print $0. La accion/es de cada regla se encierra entre un par de llaves.
Este programa imprime cada línea que contiene o la cadena 12
o la cadena 21. Si una línea contiene ambas cadenas, ésta línea es impresa
dos veces, una vez por cada regla.
Si ejecutamos este programa sobre nuestros dos ficheros de datos
de ejemplo, ListaBBS y inventarioenviado (Ver el apéndice A Ficheros de Datos para los Ejemplos),
como se muestra aquí:
awk '/12/ { print $0 }
/21/ { print $0 }' ListaBBS inventarioenviado
obtenemos la siguiente salida:
aardvark 5555553 1200/300 B
alpo-net 5553412 2400/1200/300 A
barfly 5557685 1200/300 A
bites 5551675 2400/1200/300 A
core 5552912 1200/300 C
fooey 5551234 2400/1200/300 B
foot 5556699 1200/300 B
macfoo 5556480 1200/300 A
sdace 5553430 2400/1200/300 A
sabafoo 5552127 1200/300 C
sabafoo 5552127 1200/300 C
Jan 21 36 64 620
Apr 21 70 74 514
Dese cuenta de que la línea contenida en ListaBBS que empieza
por sabafoo fue impresa dos veces, una vez para cada regla.
Aquí tienes un ejemplo para darte una idea de lo que puede hacer
un programa awk típico. Este programa muestra como awk puede ser usado para sumarizar, seleccionar y relocalizar
la salida de otra utilidad. En el ejemplo se usan características que no han
sido todavía explicadas, así que no te preocupes si no entiendes todos los detalles.
ls l ¦¦ awk '$5 == "Nov" { sum += $4 }
END { print sum }'
Este comando imprime el número total de bytes de todos los ficheros
del directorio actual que fueron modificados por última vez en Noviembre (de
cualquier año). (En el C Shell necesitarás teclear un punto y coma y después
una barra invertida al final de la primera línea; en el Shell de Bourne o el
Shell BourneAgain puedes teclear el ejemplo tal y como se muestra).
La parte de este ejemplo `ls l` es un comando que te
da un listado completo de todos los ficheros de un directorio, incluyendo el
tamaño del fichero y la fecha. La salida es algo como lo siguiente:
-rw-r--r-- 1 close 1933 Nov 7 13:05 Makefile
-rw-r--r-- 1 close 10809 Nov 7 13:03 gawk.h
-rw-r--r-- 1 close 983 Apr 13 12:14 gawk.tab.h
-rw-r--r-- 1 close 31869 Jun 15 12:20 gawk.y
-rw-r--r-- 1 close 22414 Nov 7 13:03 gawk1.c
-rw-r--r-- 1 close 37455 Nov 7 13:03 gawk2.c
-rw-r--r-- 1 close 27511 Dec 9 13:07 gawk3.c
-rw-r--r-- 1 close 7989 Nov 7 13:03 gawk4.c
El primer campo presenta los permisos de lecturaescritura, el
segundo campo contiene los enlaces al fichero, y el tercer campo identifica
al propietario del fichero. El cuarto campo contiene el tamaño del fichero en
bytes. Los campos quinto, sexto y séptimo contienen el mes, el día y la hora,
respectivamente, en la cual el fichero fue modificado por última vez. Finalmente,
el octavo campo contiene el nombre del fichero.
La expresión $5==”Nov” de tu programa awk es una expresión que chequea si el quinto campo de
la salida generada por ls l es igual a Nov. Cada
vez que una línea presenta la cadena Nov en su quinto campo, se realiza la
acción {
sum += $4 }. Esto añade el cuarto campo (el tamaño del fichero) a la variable sum.
Como resultado, cuando awk ha finalizado la lectura de líneas de entrada, sum
es la suma de los tamaños de los ficheros cuyas líneas contuvieron el patrón.
Después de que la última línea de la salida generada por ls haya sido procesada, se ejecuta la regla END, y el valor de la variable SUM se imprime. En este ejemplo, el valor de sum sería
80600.
Estas técnicas de awk
más avanzadas serán cubiertas en secciones posteriores. (Ver la sección 7. Acciones: Overview).
Antes de enseñarte la programación de awk más avanzada, debes
saber como awk
interpreta tu entrada y visualiza tu salida. Manipulando campos y usando sentencia
print, puedes producir algunos informes muy útiles y de apariencia espectacular.
Hay varias formas de ejecutar un programa awk. Si el programa es corto, es más fácil incluir el programa
en el mismo comando que ejecuta awk,
de la siguiente forma:
awk program inputfile1 inputfile2 ...
donde program consiste en una serie de patrones y acciones, según se describió anteriormente.
Cuando el programa es largo, probablemente preferirías poner
el programa en un fichero y ejecutarlo con un comando de la siguiente forma:
awk f programfile inputfile1 inputfile2 ...
Una vez que estás familiarizado con awk, escribirás con frecuencia
programas simples sobre la marcha para solucionar algo puntual. Puedes escribir
el programa como el primer argumento del comando awk, de la siguiente forma:
awk programa inputfile1 inputfile2 ...
donde programa consiste en una serie de patrones y acciones, como se describieron anteriormente.
Este formato de comando le dice al shell que ejecute
awk
y use programa para procesar los registros en el fichero(s) de entrada.
Aparecen comillas simples alrededor del programa de forma que el shell
no interprete ningún carácter awk como carácter especial del shell. Esto hace que el
shell trate programa por completo como un único argumento de awk.
Por lo tanto permite que programa tenga una extensión de varias líneas.
Este formato es también útil para la ejecución de
programas pequeños y medios desde shell scripts, porque evita la necesidad de
un fichero separado para el programa awk. Un shell script empotrado
en la línea de comando es más fiable ya que no hay otros ficheros implicados
para que se produzcan fallos.
También puedes usar awk sin ficheros de entrada. Si tecleas la siguiente línea
de comando:
awk programa
entonces awk aplica el programa a la entrada estándar, que en la mayoría de los casos es todo lo que tecleas en el terminal.
Esto continuará hasta que indiques el final de fichero mediante
la combinación de teclas Controld.
Por ejemplo, si tu ejecutas el siguiente comando:
awk '/th/'
cualquier cosa que teclees a continuación será cogido como datos para tu programa awk. Si continúas y tecleas los siguientes datos:
Kathy
Ben
Tom
Beth
Seth
Karen
Thomas
Controld
Entonces awk imprime la siguiente salida:
Kathy
Beth
Seth
como las líneas que contienen el patrón especificado th. Dese cuenta de que no reconoce “Thomas” como línea que cumpla el patrón. El lenguaje awk hace distinciones entre mayúsculas y minúsculas, y busca la concordancia con el patrón exacta. (Sin embargo, puedes evitar esto con la variable IGNORECASE. Ver la sección Sensibilidad a Mayúsculas en el Matching.)
Algunas veces, tus programas awk pueden ser muy grandes. En este caso, es más conveniente
poner el programa en un fichero separado. Para decirle a awk que use ese fichero como programa, se teclea:
awk f ficherofuente inputfile1 inputfile2 ...
El
f le dice a la utilidad awk que obtenga el programa awk
del fichero ficherofuente. Cualquier nombre de fichero puede ser usado
como ficherofuente. Por ejemplo, podrías poner el programa:
/th/
en el fichero thprog. Entonces este comando:
awk f thprog
hace la misma cosa que este otro:
awk ´/th/´
lo cual fue explicado anteriormente (ver sección Ejecutar awk sin Ficheros de Entrada). Dese cuenta que no necesitas normalmente comillas simples alrededor del nombre del fichero que especificas con f, porque la mayoría de los nombres de ficheros no contienen ninguno de los caracteres especiales de la shell.
Si quieres identificar tus ficheros con programas
awk
como tales, puedes añadir la extensión .awk a los nombres de ficheros. Esto no afecta a la ejecución
de un programa awk, pero hace que el nombre del fichero sea más legible
y fácil de localizar.
Una vez que hayas aprendido awk, podrías querer escribir scripts de awk contenidos dentro de un Shell Script ejecutable de Unix, usando el mecanismo
de script #!. Puedes hacer esto en sistemas Unix BSD y (algún día)
en GNU.
Por ejemplo, podrías crear un fichero texto llamado
hola que tuviese lo siguiente (donde BEGIN es una característica todavía no vista):
#! /bin/awk f
# un programa awk de ejemplo
BEGIN { print "Hola Mundo" }
Después de hacer este fichero ejecutable (con el comando chmod), puedes teclear simplemente:
hola
desde el shell, y el sistema ejecutará el awk del mismo modo que si hubieses tecleado:
awk f hello
Los scripts de awk
auto contenidos (introducidos dentro de un Shell Script ejecutable de Unix)
son útiles cuando quieres escribir un programa que puedan invocar los usuarios
sin que sepan que el programa está escrito en awk.
Si tu sistema no soporta el
mecanismo #!, puedes obtener un efecto similar usando un shell
script regular. Sería algo del estilo a esto:
: Los dos puntos te aseguran de que este script se ejecuta con el shell de Bourne.
awk 'program' "$@"
Usando esta técnica, es vital encerrar el program entre
comillas simples para proteger que el programa sea interpretado por el shell.
El
"$@" hace que el shell se salte todos los argumentos de la línea de comando
al programa awk, sin interpretación. La primera línea, que comienza
con un colon, se usa de forma que este shell script funcionará incluso si es
invocado por un usuario que use la CShell.
Un comentario es un texto que es incluido en
el programa para que dicho programa sea más entendible por los lectores del
mismo; no siendo los comentarios realmente parte del programa. Lo comentarios
pueden explicar que es lo que hace el programa, y cómo lo hace. Prácticamente
todos los lenguajes de programación tiene alguna forma para introducir comentarios,
ya que hay muchos programas realmente difíciles de entender sin su ayuda extra
en forma de comentarios.
En el lenguaje awk, un comentario comienza con el signo almohadilla, #,
y dicho comentario continúa hasta el final de la línea. El Lenguaje awk ignora el resto de
una línea desde el momento que encuentra un carácter #. Por ejemplo, podríamos
haber puesto lo siguiente en el programa thprog.
# Este programa encuentra registros que contengan el patrón th. De esta forma
# es como continuas el comentario en una línea adicional.
/th/
Bastante a menudo, cada línea en un programa awk
es una sentencia separada o regla separada, como esta:
awk /12/ { print $0 }
/21/ { print $0 } ListaBBS inventarioenviado
Pero algunas veces una sentencia puede ocupar más
de una línea, y una línea puede contener varias sentencias. Puedes partir una
sentencias en múltiples líneas insertando un carácter newline (salto de línea)
detrás de alguno de los siguientes caracteres:
, { ? : ¦¦ && do else
Un carácter newline el cualquier otro punto es considerado
como el final de una sentencia.
Si te gustaría partir una única sentencia en dos líneas
en un determinado punto en el cual un carácter newline terminaría dicha sentencia,
puedes continuarla finalizando la primera línea con un carácter de barra invertida,
\. Esto esta permitido absolutamente en cualquier sitio de la sentencia, incluso
en mitad de una cadena o expresión regular. Por ejemplo:
awk '/Este programa es demasiado grande, así que continua \
en la línea siguiente / { print $1 }'
Nosotros no hemos utilizado, por norma, el uso de
la continuación de una línea mediante la barra invertida en los programas de
ejemplo de este manual. Ya que no hay límite en la longitud de una línea, nunca
es estrictamente necesario particionar ésta; es simplemente por cuestión de
estética. La continuación mediante barra invertida es muy útil cuando tu programa
awk
está en un fichero fuente independiente, en lugar de ser tecleado en la línea
de comandos.
Precaución: la continuación de línea usando la barra invertida
no funciona tal y como se describe aquí bajo la C Shell.
La continuación con barra invertida funciona en tus ficheros con programas awk, y también en los programas que se lanzan escribiéndolos
directamente en la línea de comandos teniendo en cuenta que estés usando el
Bourne shell o Bourneagain Shell. Pero el C shell usado en Unix Berkeley se
comporta de forma diferente! Bajo este Shell, debes usar dos barras invertidas
en una fila, seguido por un carácter newline.
Cuando las sentencias awk dentro de una regla son cortas, podrías desear poner
más de una en una misma línea. Se puede hacer esto separando las sentencias
mediante puntos y coma ;. Esto se aplica también a las mismas reglas. Por lo
que, el programa de más arriba se podría haber escrito:
/12/ { print $0 } ; /21/ { print $0 }
Nota: el requerimiento de que las reglas en la misma línea deben ser separadas
por puntos y comas es un cambio reciente en el Lenguaje awk;
fue hecho por consistencia con el tratamiento de las sentencias dentro de una
acción.
Te estarás preguntando: ¿qué uso le puedo yo dar a
todo esto? Utilizando programas de utilidades adicionales, patrones más avanzados,
separadores de campo, sentencias aritméticas, y otros criterios de selección,
puedes producir una salida mucho más compleja.
El lenguaje awk es muy útil para producir informes a partir de grandes
cantidades de datos raw, tales como información de sumarización a partir de
la salida de otros programas de utilidades tales como ls. (Ver la sección Un ejemplo más complejo).
Los programas escritos con awk son a menudo mucho más pequeños de lo que serían en
otros lenguajes. Esto hace que los programas awk
sean más fáciles de componer y usar. A menudo los programas awk
pueden ser compuestos rápidamente en tu terminal, usados una y múltiples veces.
Debido a que los programas de awk son interpretados, puedes evitar el ciclo de desarrollo
de software normal.
Han sido escritos en awk programas complejos, incluido un completo ensamblador
para microprocesadores de 8 bits (Ver la sección 18. Glosario,
para más información) y un ensamblador microcodificado para una computadora
Prolog de propósito especial. Sin embargo, las posibilidades de awk van más allá de tales complejidades.
Si te encuentras a ti mismo escribiendo scripts de
awk
de más de, digamos, unos pocos de cientos de líneas, podrías considerar usar
un lenguaje de programación diferente. Emacs Lisp es una buena elección si necesitas
cadenas sofisticadas o capacidades de búsqueda de patrones. El shell también
está bien para búsqueda de patrones y cadenas; además, te permite el potente
uso de utilidades del sistema. Lenguajes más convencionales, tales como C, C++,
y Lisp, te ofrecen mejores facilidades para la programación de sistema y para
manejar la complejidad de grandes programas.
Manual |