AWK: una interesante herramienta

Rino Rondán, coordinador de la carrera Linux de EducacionIT, nos presenta esta herramienta que funciona dentro de ambientes Unix. Conoce la historia de Awk así como algunos ejemplos de ejecución de comandos. 

Antes de comenzar a ver un poco esta herramienta, vamos a hacer referencia a su historia y conceptos:

AWK es un lenguaje de programación diseñado para procesar datos basados en texto, ya sean ficheros o flujos de datos. El nombre AWK deriva de las iniciales de los apellidos de sus autores: Alfred Aho, Peter Weinberger, y Brian Kernighan. awk, cuando está escrito todo en minúsculas, hace referencia al programa de Unix o Plan 9 que interpreta programas escritos en el lenguaje de programación AWK.

AWK es ejemplo de un lenguaje de programación que usa ampliamente el tipo de datos de listas asociativas (es decir, listas indexadas por cadenas clave), y expresiones regulares. El poder, brevedad, limitaciones de los programas de AWK y los guiones de sed inspiraron a Larry Wall a escribir Perl. Debido a su densa notación, todos estos lenguajes son frecuentemente usados para escribir programas de una línea.

AWK fue una de las primeras herramientas en aparecer en Unix (en la versión 3) y ganó popularidad como una manera de añadir funcionalidad a las tuberías de Unix.

La implementación de alguna versión del lenguaje AWK es estándar en casi todo sistema operativo tipo unix moderno. AWK es mencionado en las Single UNIX Specification (especificaciones básicas de Unix) como una de las utilidades necesarias de todo sistema operativo Unix. Se pueden instalar implementaciones de AWK en casi todos los demás sistemas operativos (http://es.wikipedia.org/wiki/AWK)

 

También tenemos gawk

GNU awk, o gawk, es otra implementación libre. Fue escrita antes de que la original fuera publicada, y es ampliamente utilizada. Casi toda distribución Linux incluye una versión actualizada de gawk y es reconocido como la implementación estándar en el mundo linux. La versión 30 de GAWK fue incluida como awk en la versión 5.0 de FreeBSD.

Las versiones posteriores de BSD incluyeron awk para evitar el uso de las GPL, unas licencias de software libre más restrictivas que las BSD en el sentido de que un programa publicado bajo la licencia GPL, no puede ser modificado para convertirse en propietario.

Para empezar y antes de ejecutar algún comando deberían saber algunas cosas:

Podemos usarlo básicamente de tres formas:

 

Desde la línea de comandos:

ps auxwww |awk '{print $1}'

 

Desde un archivo que contiene lo que necesitamos hacer:

awk -f programa.awk archivo_de_entrada

o

desde un script:

Especificando su intérprete

#!/usr/bin/awk –f

 

Primer Ejemplo:

 

Partamos de un ejemplo sencillo que es mostrar los registros que usamos en la entrada hacia la salida.

 [root@restauracion tuxinfo]# ls -l |awk
'{print}'
total 0
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo1
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo2
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo3
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo4
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo5
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo6
[root@restauracion tuxinfo]#

Como verán, este ejemplo nos mostró lo mismo que el comando ls l, en donde por cada registro que recibo del comando anterior, no hizo falta definir ningún ciclo. Podríamos decir que a medida que recibe los registros, le aplica algún filtro/patrón/función y otras cosas más complejas.

Vamos ahora a dividir un poco la entrada, para que en la salida obtenga algo más específico, como por ejemplo un campo dado:

El comando ls l nos devuelve en varias líneas esta información, donde cada línea es un registro que está divido en campos, si quisiéramos obtener el campo del nombre del archivo necesitaríamos especificar el campo 9

total 0
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo1
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo2
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo3
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo4
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo5
-rw-r--r-- 1 root root 0 Dec 16 01:47 tuxinfo6

 

Esto se haría así: 

[root@restauracion tuxinfo]# ls -l |awk '{print
$9}'
tuxinfo1
tuxinfo2
tuxinfo3
tuxinfo4
tuxinfo5
tuxinfo6
 

Como verán tenemos una línea en blanco, esto se debe a que el primer registro es corto y contiene sólo un campo.

Los campos se indican con $# seguido del número de posición, también los separadores de campos se pueden cambiar. En este caso el separador está contemplado como un espacio, o en algunos casos como tabulaciones.

Si quisiéramos poner otro separador de campo, podríamos probar con el archivo /etc/passwd (donde el separador es el “:”)

root:x:0:0:root:/root:/bin/bash

 

Si quisiera capturar las primeras tres capturas:

[root@restauracion tuxinfo]# awk -F":" {'print
$1}' /etc/passwd | head -n3
root
bin
daemon

 

Otra cosa a destacar es que al final del Awk es donde le debo indicar qué archivo va a utilizar de entrada, sino tendría que haber puesto:

cat /etc/passwd | awk -F":" {'print $1}'

 

Si llegase a usar $0 estaría usando todo el registro.

Antes de seguir avanzando, podríamos ver un uso más cotidiano y simple para entender un poco cómo se usa este comando. Debemos tener en cuenta que lo que vamos hacer, se puede realizar de diferentes maneras con otras herramientas. Chequeamos que tenemos un proceso ejecutándose muchas veces

 

[root@restauracion tuxinfo]# ps aux |grep tux
crond1 19363 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19701 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19703 0.0 0.0 112056 1324 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19815 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19837 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19839 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19970 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19972 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19975 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 20105 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
root 23165 0.0 0.0 109404 864 pts/4
S+ 02:06 0:00 grep --color=auto tux

 

Luego con Awk listamos sólo para obtener el número de proceso

[root@restauracion tuxinfo]# ps aux |grep tux
|awk '{print $2}'
19363
19701
19703
19815
19837
19839
19970
19972
19975
20105
26677
[root@restauracion tuxinfo]#

 

Si a esto le agregamos xargs

[root@restauracion tuxinfo]# ps aux |grep tux
|awk '{print $2}' |xargs echo kill
kill 2844 19363 19701 19703 19815 19837 19839
19970 19972 19975 20105
[root@restauracion tuxinfo]#

Obtenemos el comando entero listo para ejecutar (basta sacar del comando la opción echo, pero hay que estar seguro porque sólo ejecuta una)

Este fue un ejemplo sólo para entender qué podemos hacer con el comando.

Ahora un último ejemplo para ir cerrando:

[root@restauracion tuxinfo]# ps aux | awk
'/tux/ && !/root/ '
crond1 19363 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19701 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19703 0.0 0.0 112056 1328 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19815 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19837 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19839 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19970 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19972 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 19975 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
crond1 20105 0.0 0.0 112056 1332 pts/5
S 02:05 0:00 /bin/bash ./tux
[root@restauracion tuxinfo]#

 

Como verán no usamos un grep pero ya estamos en frente de nuestro primer patrón, en este caso estamos diciendo que analice aquellos registros que contienen en algún lado la cadena tux y que a la vez no contenga la cadena root. Así de este modo no queda en la lista el

mismo proceso que se ejecuta al utilizar el comando awk (que sería algo como esto: root 25901 0.0 0.0 112412 1088 pts/4 S+ 02:14 0:00 awk /tux/).

De esta forma obtengo lo que estoy buscando y sé que la columna dos va a contener los procesos que necesito trabajar.

Algo más completo y, quizás real:

[root@restauracion tuxinfo]# for i in $(ps aux
| awk '/tux/ && !/root/ {print $2}') ; do
echo renice -n 15 $i; done
renice -n 15 19363
renice -n 15 19701
renice -n 15 19703
renice -n 15 19815
renice -n 15 19837
renice -n 15 19839
renice -n 15 19970
renice -n 15 19972
renice -n 15 19975
renice -n 15 20105
[root@restauracion tuxinfo]#

 

De esta forma estamos utilizando un ciclo for para que capture cada registro que el awk procesa con sus filtros correspondientes, luego ese valor se instancia en la variable i para que el comando echo imprima en la salida estándar el comando que necesitaría ejecutar poniendo el valor i correspondiente en cada ciclo.

Una forma también de probarlo es ejecutar lo que está adentro del paréntesis y luego buscar la forma de ponerlo en el bucle. Con la práctica sale escribir todo de una sola vez, pero lo recomendable es ir paso a paso.

 

Rino Rondán

Coordinador de Carrera Linux en EducacionIT

 

Carrera Relacionada: Carrera Linux

 

 

 

 

 

 

Fuente: Tuxinfo

 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *