Awk es una de esas herramientas misteriosas para procesar texto incluidas en las distribuciones *NIX.
Sirve, por ejemplo, para:
- extraer información de ficheros de texto y generar informes;
- convertir ficheros de uno a otro formato;
- realizar operaciones matemáticas con datos numéricos (extraídos, claro está, de un fichero de texto).
Y se usa, en muy resumidas cuentas, tal que así:
awk '<expresión> {<acción>}'
Como quiera que en awk, como en casi todo, soy un novato, no pretendo escribir un tutorial. Me limitaré a colocar aquí un recordatorio (sí, otro) en beneficio de mi pobre memoria. En concreto un par de soluciones a un par de problemas comunes en la oficina.
Problema número uno: códigos postales
Tenemos un fichero de direcciones postales, pero nuestra torpeza habitual ha hecho que los códigos postales por debajo del 10000 se hayan grabado con cuatro dígitos (es decir, tenemos 1001 donde deberíamos tener 01001).
El fichero origen tiene la siguiente estructura:
12345|Fernando López|San Luis, 7|1001|Vitoria|Álava
6789|Joaquín Costa|Avda. Juan Pablo II, 7|8009|Barcelona|Barcelona
etc.
Salta a la vista que:
- el delimitador de campos es un «pipe» (
|); - el código postal está en el cuarto campo.
Vamos a por el comando que salvará nuestras vidas:
- para indicar a awk el carácter delimitador (por defecto es el espacio), utilizamos el parámetro
-F. Como el pipe es un carácter especial, tendremos que escaparlo (\|); - no necesitamos utilizar ningún patrón de búsqueda, puesto que nos interesa procesar todas las líneas, así pues, lo omitimos;
- especificaremos el formato de salida mediante el uso de
printf, para rellenar con ceros la parte izquierda de los códigos postales cortos, basta con utilizar el formato%05d. El resto de los datos pasan sin procesar (%s).
La orden queda tal que así:
awk -F\| '{printf "%s|%s|%s|%05d|%s|%s", $1, $2, $3, $4, $5, $6}' input.txt > output.txt
(Donde input.txt es el fichero de entrada y output.txt el de salida.)
Problema número dos: extraer datos de un listado de directorio
En la empresa donde trabajo, hemos desarrollado un sistema para que los clientes puedan actualizar sus direcciones en nuestra base de datos. Como quiera que el cliente, a pesar de tener razón, suele ser poco de fiar, la actualización no se realiza «en vivo». En su lugar, las modificaciones son enviadas por correo electrónico para que el personal las revise e introduzca, esta vez sí, en la base de datos.
Pero —siempre hay un pero—, el correo electrónico tiene un pequeño defecto: a veces falla. Así que para evitar la pérdida de datos críticos, antes de realizar el envío del email, se hace una copia de su contenido en un fichero de texto (bueno, en realidad es un fichero HTML, pero para el caso, patatas). Esas copias, como no, van a parar a un directorio de backup.
El contenido de dicho directorio sirve, además de para evitar fallos, para comprobar de cuando en cuando que se han realizado todas las modificaciones.
Cada fichero se nombra de la siguiente manera: código_cliente-fechaISO.hora.html. Para obtener los códigos de los clientes, comenzamos por obtener un listado de los ficheros HTML del directorio (ls *.html). Pasamos la salida del comando vía «pipe» a awk, que tomará del nombre del archivo la subcadena que va del principio del mismo hasta el primer guión.
En resumen:
ls *.html | awk '{print substr($1, 1, index($1, "-") - 1)}'
Si además somos tan chulos que queremos la salida ordenada por códigos, he aquí otra solución (el modificador -g hace que sort ordene numéricamente.):
ls *.html | awk '{print substr($1, 1, index($1, "-") - 1)}' | sort -g
Para saber más:
- An Awk Tutorial (en inglés);
- Awk (en español), dentro del Curso de Unix escrito por jagar1;
- enlaces en del.icio.us agrupados en la etiqueta ‘awk’;
man awk;- cualquier otra cosilla que puedan sugerir nuestros amables lectores.


Un comentario RSS
Problema: extraer fechas de un listado