Vous êtes sur la page 1sur 2

Mini tutorial de awk El blog de Deigote

Page 1 of 6

El blog de Deigote
El mundo de Deigote. Un diario de cualquier cosa que me resulte interesante (si a alguien ms se lo resulta, es
otro cantar). Espero que os guste o disguste. Incluso que os deje indiferentes sera una opcin tan buena como
cualquier otra.





Blog
Acerca de
Comentarios
Archivos

Bill Gates en la Facultad


Ratbert dijo

Mini tutorial de awk


Publicado el Agosto 30, 2006 en Informtica, internet y tecnologa.
script, scripting, tutorial, unix.

26 Comentarios

Etiquetas: awk, linux,

Por peticin popular, voy a escribir un poco sobre un mandato tpico de los sistemas operativos UNIX (apareci por
primera vez en 1977 nada menos), awk.
awk es un mandato que sirve para procesar lneas de texto (separadas, naturalmente, por un salto de lnea). awk cuenta
con un pequeo y sencillo lenguaje de programacin que es interpretado (no necesita ser compilado), y resulta
tremendamente til cuando queremos extraer informacin de extensos campos de texto (y, posiblemente, manipularla).
El funcionamiento del madato awk es muy sencillo: basicamente tenemos dos posiblidades:

$ awk -f fuente.awk fichero_entrada.txt

$ awk 'fragmento de cdigo fuente' fichero_entrada.txt


En la primera de ellas, el cdigo fuente est en un fichero (recomendado para usos que vayan a repetirse con el tiempo
y con cdigos fuentes largos) mientras que el segundo ofrece la ventaja de poder poner el cdigo fuente como un
argumento ms. Esto es muy til para el uso de awk en scripts o similares, en los que el uso de ficheros puede ser un
engorro. Tambin cabe la posibilidad de omitir el fichero de entrada, en cuyo caso awk leer de la entrada estndar.
Respecto al lenguaje awk, tiene una estructura similar a lo siguiente:

BEGIN { accin }
/patrn/ { accin }
END { accin }
La forma de funcionamiento la siguiente:
1. Nada ms comenzar la ejecucin, se evaluar la accin marcada entre llaves precedida por la palabra reservada
BEGIN.
2. Por cada campo de texto (recordemos, por defecto lneas) awk evaluar si se ajusta al patrn (una expresin
regular), y de ser as, ejecutar la accin marcada entre llaves que sigue a dicho patrn. Por cada lneas se
evaluarn todos los patrones a menos que en una de las acciones ejecutadas se encuentre la orden next, en cuyo
caso se comenzar desde el principio con la siguiente lnea.
3. Finalmente, se procesar la accin marcada entre llaves precedida por la palabra reservada END.
Respecto a los patrones de awk, son, como ya he dicho, expresiones regulares. No voy a explicar aqu todas las
posiblidades porque no acabara nunca (y con la ayuda de la Wikipedia os debera bastar), basten un par de ejemplos:


/[afP]MEMOLO[1-3]z/ casar con cualquier lnea que contenga las letras a, f o P seguidas de la cadena
MEMOLO seguidas de un dgito comprendido del 1 al 3 y seguida por la letra z.
/[afP](MEMOLO)+([1-3])*z/ casar con cualquier lnea que contenga las letras a, f o P seguidas de la cadena
MEMOLO una o varias veces seguidas de un dgito comprendido del 1 al 3 que puede aparecer ninguna, una, o
varias veces y seguida por la letra z.

Esta es la parte ms complicada de awk (ya sabeis lo que se dice de las expresiones regulares).
En cuanto a las acciones, cualquiera que haya programado en C no tendr mucho problema, ya que es similar. Como
caractersticas cabra destacar:


El acceso a las lnea actual se hace mediante unas variables especiales. En concreto $0 referencia a toda la lnea
mientras que $1, $2, etctera, referencian a los campos de dicha lnea. El separador de campos por defecto es un
espacio o un tabulador, pudindose modificar en la accin de BEGIN con la variable FS (otra expresin regular,
por cierto).
No es necesario declarar ni tipar las variables, cuyo formato es el mismo que en C (su expresin regular, para que
vayais practicando, es algo parecido a [a-Z]([a-Z] | [1-9] | _ )*).
Estn permitidas todas las estructuras clsicas de programacin en un formato estilo C (bucles, expresiones
condicionales, operadores, etctera).
Para imprimir resultados, existen dos posiblidades. La primera, print, es la ms cmoda, puesto que no es
necesario usar parntesis para sus argumentos y cuenta con concatenacin automtica de los mismos (algo
parecido al mandato echo de la terminal. Por ejemplo, print la lnea $0 tiene NF palabras imprimir la
frase que precede a print sustituyedo $0 por la lnea actual y NF (otra variable especial) por el nmero de campos
de la misma. Como segunda posibilidad, tenemos printf, que ofrece mayor control (es idntico al del lenguaje C).

Y qu pasa con los los jugosos ejemplos? Pues he recopilado alguno que otro segn me ha ido surgiendo la necesidad
de usarlo estos das.


Por ejemplo, el otro da necesitaba obtener del fichero de log de Tomcat las lneas que contuviesen o bien
SOAP21 o bien 2 . Esto sera sencillo de hacer con dos grep, pero yo necesitaba que esas lneas
mantuviesen el orden en el que haban aparecido en el fichero, y hacer eso con un grep requiere de una expresin
regular bastante ms compleja de lo que en realidad es necesario. Adems, quera saber en qu nmero de lnea
del fichero estaba cada lnea buscada. Con awk, fue tan sencillo como esto:

cat tomcat.log | awk '/SOAP21/{print NR " - " $0} / - 2/


{print NR " - "$0}'


Tambin necesit, en el mismo fichero, verificar que se cumpliese una secuencia, y concretamente, me vala
saber que, dentro del conjunto de lneas que contenan SOAP21, las mltiplo de 5 eran idnticas, ya que de esta
manera saba que se haban cumplido todos los pasos. Por lo tanto, necesitaba sacar las lneas que tuviesen
SOAP21, y dentro de stas, slo las que su nmero de lnea fuese mltiplo de 5. Nuevamente, awk te lo pone
fcil:

http://blog.deigote.com/2006/08/30/mini-tutorial-de-awk/

04-01-2011

Mini tutorial de awk El blog de Deigote

Page 2 of 6

cat tomcat.log | awk 'BEGIN { nl = 1 } /SOAP21/ { if (nl % 5


== 0) print ; nl++}'


En plan ms complicado (teniendo en cuenta que lo de antes era trivial), hice una pequea lnea para sacar la
nota media a partir del archivo html que te devuelve la UPM cuando consultas tu expendiente usando la
modalidad ltimo estado de cada asignatura (aunque falla cuando tienes alguna matrcula, pero bueno, eso no
es lo importante ahora). El cdigo es el siguiente:

cat consulta.upm.html | grep "


/<\/table>/ { d = 0 } { if (d > 0) { if (c == 10) { print ;
c = 0 } else c++ } }' | grep
'>\([1-9][0-9]\|[1-9]\|[1-9]\,[0-9]\{1\}\|[1-9]\,[0-9]\{2\}
\)<' | cut -d 1 -f2 -d'>' | cut
-f1 -d'<' | awk 'BEGIN { t=0.0;n=0; } {print ; t=t+$1 ; n++}
END { print "Total " t "
Asignaturas " n " Media " t/n}'
Como veis, el primer fragmento de awk hace una seleccin de lneas, imprimiendo slo las filas de las tablas que
sean mltiplo de 10 (son en las que se encuentran las notas) y que estn contenidas entre una lnea que tenga la
palabra Obs y el primer final de tabla en html. Una vez obtenidas estas lneas, uso grep para quedarme solo con
las que tienen nota y cut para dejar slo la nota, quitando el resto de elementos html. El segundo fragmento de
awk se encarga de ir sumando las notas y el nmero de asignaturas para imprimir la media.
EDITO: ir aadiendo ms fantabulosos ejemplos


segn me los vaya encontrado.

Mi hermano el otro da me pregunt como resolvera un problema y le suger que usara awk. El problema
consista en que tena ficheros (por cierto, de ms de 80.000 lneas) con una estructura tal que

frase1 1
frase2 5
...
fraseN M
y quera sumar los nmeros de cada frase. En el caso original tena la ventaja de que las frases siempre iban en el
mismo orden en todos los ficheros, pero la sencillez de awk hace que la solucin (que corre a cargo de mi
hermano, por cierto) valga para casos que no estn en orden (e incluso que aparezcan frases en algunos ficheros y
en otros no). Adems, se requera que fuese relativamente rpido, y awk cumpli con las expectativas (la solucin
previa eran pruebas con scripts ms o menos a mano y los resultados se iban por encima de los 10 minutos, frente
a los 2 minutos de la solucin con awk). El nico problema era juntar la salida de los ficheros, pero awk permite
trabajar con varios ficheros de entrada de datos (si no, un poquito de bash scripting, for i in *.out ; do cat $i ;
done, lo hubiese solucionado). Los ficheros tenan extensin .out, por lo que la solucin final es:

awk 'BEGIN { FS = " ";} { resultados[$1] += $2 } END { for


(category in resultados) print category, resultados
[category]; } *.out'
Como veis es sencillo, limpio y eficaz
con awk, la suciedad se va en un bang! Aqu adems podeis ver
algunas cosas ms de awk, como los bucles, los array (estilo PHP, sin declaracin ni reserva de memoria ni
inicializacin de datos) y la variable especial FS, que sirve para especificar cmo separar los campos de una lnea
(aunque en este caso no haga falta porque por defecto es espacio o tabulador).
Y esto es todo por hoy. Huelga decir que en Internet encontrareis cientos de ejemplos y tutoriales, pero yo quera hacer
una pequea introduccin con un par de ejemplos ms prcticos que los que suelo encontrar (al menos, seran prcticos
para m ;-)). Espero que os sea de utilidad.

Parecidos razonables
Si la salida fuese un Excell, lo llamaramos ingeniera del software Diciembre 11, 2008 10
Creando ficheros tipo JAR de Java en Unix (slo clases) Octubre 31, 2007 3
Musepack MPC a MP3 en Ubuntu Linux Enero 15, 2008 2
Mas sobre firewall y account Septiembre 11, 2005 0
Firewalling/accounting con iptables, averiguar la IP y algunas cosas ms Septiembre 9, 2005

26 Respuestas a Mini tutorial de awk


Canal RSS de esta Entrada Direccin Trackback

SPQR
Agosto 30, 2006 | 18:50
adafd

Deigote
Agosto 30, 2006 | 18:54
Gracias por tu ayuda SPQR

kike
Agosto 31, 2006 | 01:06
Justo lo que necesitaba.
PD :
grep -n SOAP21 tomcat.log no hace lo del primer ejemplo?
Aunque si tienen que ser las dos expresiones en el mismo comando no lo he conseguido.He probado distintas
combinaciones pero no coge (A|B), no se por qu. El man grep incluso habla explicitamente de separar
expresiones con |, pero nada.

Deigote
Agosto 31, 2006 | 09:46

http://blog.deigote.com/2006/08/30/mini-tutorial-de-awk/

04-01-2011

Vous aimerez peut-être aussi