Por petición popular, voy a escribir un poco sobre un mandato típico de los sistemas operativos UNIX (apareció por primera vez en 1977 nada menos), awk.
awk es un mandato que sirve para procesar líneas de texto (separadas, naturalmente, por un salto de línea). awk cuenta con un pequeño y sencillo lenguaje de programación que es interpretado (no necesita ser compilado), y resulta tremendamente útil cuando queremos extraer información 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 código fuente' fichero_entrada.txt
En la primera de ellas, el código fuente está en un fichero (recomendado para usos que vayan a repetirse con el tiempo y con códigos fuentes largos) mientras que el segundo ofrece la ventaja de poder poner el código fuente como un argumento más. Esto es muy útil para el uso de awk en scripts o similares, en los que el uso de ficheros puede ser un engorro. También cabe la posibilidad de omitir el fichero de entrada, en cuyo caso awk leerá de la entrada estándar.
Respecto al lenguaje awk, tiene una estructura similar a lo siguiente:
BEGIN { acción }
/patrón/ { acción }
END { acción }
La forma de funcionamiento la siguiente:
- Nada más comenzar la ejecución, se evaluará la acción marcada entre llaves precedida por la palabra reservada BEGIN.
- Por cada campo de texto (recordemos, por defecto líneas) awk evaluará si se ajusta al patrón (una expresión regular), y de ser así, ejecutará la acción marcada entre llaves que sigue a dicho patrón. Por cada líneas se evaluarán 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 línea.
- Finalmente, se procesará la acción 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 acabaría nunca (y con la ayuda de la Wikipedia os debería bastar), basten un par de ejemplos:
- /[afP]MEMOLO[1-3]z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO seguidas de un dígito comprendido del 1 al 3 y seguida por la letra z.
- /[afP](MEMOLO)+([1-3])*z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO una o varias veces seguidas de un dígito comprendido del 1 al 3 que puede aparecer ninguna, una, o varias veces y seguida por la letra z.
Esta es la parte más 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 características cabría destacar:
- El acceso a las línea actual se hace mediante unas variables especiales. En concreto $0 referencia a toda la línea mientras que $1, $2, etcétera, referencian a los campos de dicha línea. El separador de campos por defecto es un espacio o un tabulador, pudiéndose modificar en la acción de BEGIN con la variable FS (otra expresión regular, por cierto).
- No es necesario declarar ni tipar las variables, cuyo formato es el mismo que en C (su expresión regular, para que vayais practicando, es algo parecido a [a-Z]([a-Z] | [1-9] | _ )*).
- Están permitidas todas las estructuras clásicas de programación en un formato estilo C (bucles, expresiones condicionales, operadores, etcétera).
- Para imprimir resultados, existen dos posiblidades. La primera, print, es la más cómoda, puesto que no es necesario usar paréntesis para sus argumentos y cuenta con concatenación automática de los mismos (algo parecido al mandato echo de la terminal. Por ejemplo, print “la línea ” $0 “tiene ” NF ” palabras” imprimirá la frase que precede a print sustituyedo $0 por la línea actual y NF (otra variable especial) por el número de campos de la misma. Como segunda posibilidad, tenemos printf, que ofrece mayor control (es idéntico al del lenguaje C).
¿Y qué pasa con los los jugosos ejemplos? Pues he recopilado alguno que otro según me ha ido surgiendo la necesidad de usarlo estos días.
Y esto es todo por hoy. Huelga decir que en Internet encontrareis cientos de ejemplos y tutoriales, pero yo quería hacer una pequeña introducción con un par de ejemplos más prácticos que los que suelo encontrar (al menos, serían prácticos para mí ;-)). Espero que os sea de utilidad.