Skip to main content
Descubriendo el potencial de AWK

Descubriendo el potencial de AWK

AWK es uno de los comandos más poderosos en Linux, el cual ofrece un mayor control a la hora de procesar datos provenientes de otros comandos, además de poder utilizar operadores lógicos, variables, funciones de impresión…

Bienvenidos de nuevo a Byte Mind, en este caso vamos a hablar de AWK, uno de los comandos más poderosos de Linux debido a su capacidad de procesamiento de datos, a través del cual se pueden utilizar operadores lógicos, variables, funciones de impresión, etc.

AWK significa “Aho, Weinberger y Kernighan” y se utiliza principalmente para escanear y procesar patrones. Se puede utilizar para la búsqueda de patrones en uno o varios ficheros a la vez, en la salida de otros comandos. Vamos a ver como es su sintáxis básica y luego explicaremos las posibilidades de este comando así como ejemplos de las mismas.

 

Sintáxis básica de AWK

La sintáxis básica de AWK sería la siguiente:

AWK puede tomar los siguientes argumentos

  • -F fs -> se utiliza para especificar un separador de archivos.
  • -f archivo -> se utiliza para especificar un archivo que contiene un script awk.
  • -v var = valor -> se utiliza para declarar una variable.

Hemos generado un fichero con una serie de datos que utilizaremos en los ejemplos de este post e imprimiremos su contenido directamente con awk:

En el primer ejemplo no utilizamos ningún patrón así que vamos a usar uno, por ejemplo, imprimir aquellos usuarios del departamento de cuentas:

Visto un primer ejemplo, vamos a profundizar en cada una de las posibilidades que nos da este comando.

 

Como se ha indicado también es posible guardar nuestro código en un fichero y luego cargar el mismo con awk.

Utilizaremos el código del último ejemplo, supongamos que tenemos el siguiente fichero de awk:

Y llamamos al mismo con awk para que aplique el mismo al procesar el fichero:

 

Operadores en AWK

Operadores matemáticos

En AWK es posible utilizar los siguientes operadores matemáticos

  • +, -, *, / -> Suma, Resta, Multiplicación y División.
  • % -> Operador módulo o resto.
  • ++, — -> Operador de incremento y decremento.
  • +=, -=, *=, /=, %= -> Al igual que en otros lenguajes como C. (x += 1 sería equivalente a x = x + 1)

 

Operadores de búsqueda

Como ya hemos visto en la sección anterior es posible realizar búsquedas en base a cadenas de texto, a continuación se muestran los posibles operadores a utilizar para ello:

  • /string/ -> busca la cadena indicada.
  • /^string/ -> busca la cadena al principio de la línea.
  • /string$/ -> busca la cadena al final de la línea.
  • $N ~ /string/ -> busca la cadena en el campo N.
  • $N !~ /string/ -> busca la cadena a excepción del campo N.
  • /(string1)|(string2)/ -> busca la cadena 1 o la cadena 2.
  • /string1/,/string2/ -> busca todas las líneas entre cadena 1 y cadena 2.

 

Variables en AWK

AWK viene por defecto con algunas variables integradas para el procesado de archivos de texto. Vamos a verlas por partes en función de las carácterísticas de cada una de ellas.

Variables básicas

Un uso básico de variables permitiría indicar que campos queremos obtener de cada una de las líneas, para ellos se utilizarían las siguientes variables:

  • $0 -> se utiliza para mostrar la línea completa
  • $1-$n -> mostrará los campos (columnas) de la línea especificada

En el siguiente ejemplo, imprimiremos el primer campo de cada línea:

Por defecto, AWK, utiliza el espacio o el TAB como separador, aunque habrá ocasiones en que esto no sea útil, para ello imprimiremos el fichero /etc/passwd, el cual utiliza el carácter : como separador.

En este caso podemos utilizar el parámetro -F para indicar el mismo, como se ve en el siguiente ejemplo:

 

Variables integradas

Ya hemos visto que las variables de campo de datos ($1, $2…) son utilizadas para extraer datos de un campo en concreto, y que además deberemos lidiar con el separador FS.

Pero estas no son las únicas variables, existen más variables como son las siguientes:

  • FIELDWIDTHS -> especifica el ancho del campo.
  • FS -> contiene el carácter separador de campo (espacio o TAB por defecto) y se utiliza para dividir campos.
  • OFS -> almacena el separador de campo de salida y se utiliza para separar los campos cuando AWK los imprime
  • ORS -> almacena el separador de líneas de salida y se utiliza para separa las líneas cuando AWK las imprime
  • RS -> almacena el carácter separador de la línea actual

Vamos a ver algún ejemplo de las mismas, por ejemplo, la variables OFS, por defecto, es el carácter espacio, pero puedes establecer esta variable para que especifique el separador que necesitas:

En el ejemplo anterior, hemos sustituido el separador utilizado en el fichero, el cual indicamos con la variable FS, y hemos modificado el mismo por un – mediante la variable OFS. Además hemos utilizado la variable BEGIN, utilizada para el preprocesamiento de texto, pero tranquilos, esta la veremos en detalle más adelante.

Veamos otro ejemplo, para este, habrá ocasiones en que nos encontramos con campos distribuidos sin un separador fijo, en estos casos la variable FIELDWIDTHS puede resolver el problema.

Teniendo el siguiente contenido:

Podemos separar los campos en bloques del mismo tamaño con FIELDWIDTHS

Para el siguiente ejemplo, hemos generado otro fichero, donde los datos están distribuidos en varias líneas, y como separador entre los datos se usa una línea vacía

Utilizaremos a continuación AWK para establecer la variables FS con el carácter de salto de línea (\n) y la variable RS como texto en blanco para que las líneas vacías sean consideradas separadores:

Perfecto! ahora podemos ver los registros y campos de una forma más amigable.

 

Algunas variables más

Además de las variables que ya vimos anteriormente, existen otras que pueden ayudar a obtener más información:

  • ARGC -> devuelve el número de parámetros pasados.
  • ARGV -> devuelve los parámetros por la línea de comandos.
  • ENVIRON -> es un arreglo de las variables de entorno del shell y sus respectivos valores.
  • FILENAME -> devuelve el nombre del archivo que está siendo procesado.
  • FNR -> a través de la misma se puede acceder al registro que está siendo procesado.
  • IGNORECASE -> se utiliza para indicar que ignore las diferencias entre mayúsculas y minúsculas.
  • NF -> especifica el número total de campos en la línea actual.
  • NR -> especifica el número total de líneas en el fichero/stream a procesar.

 

Vamos a ver a continuación en ejemplo como funciona alguna de ellas.

En el primer ejemplo, vamos a obtener los parámetros pasados, así como el segundo parámetro pasado a awk

La variable ENVIRON devuelve las variables de entorno, y podemos especificar que variable queremos obtener

La variable NF especificará el último campo de cada línea, sin importar su posición:

Con la variable FNR podemos ver la línea que está siendo procesada

Si procesamos dos ficheros, veremos la diferencia entre NR y FNR

La variable FNR nos mostrará la línea procesada en cada fichero de forma individual, mientras que la variable NR mostrará el total de líneas que han sido procesadas.

 

Variables definidas por el usuario

Las variables definidas pueden tener cualquier nombre, pero no pueden empezar con un número.

Se pueden definir de dos formas, mediante el parámetro -v o en el propio código, veámoslo con dos ejemplos:

En este primero lo definimos como parámetro:

En el segundo lo incluimos en el preprocesado de awk:

 

Pre Procesamiento de los datos

Para poder modificar el comportamiento de la salida, antes de que se lleve a cabo el procesamiento de los datos se utiliza la palabra clave BEGIN. Como ya se vió anteriormente, se utiliza también cuando se quiere definir una variable.

En este caso, como ejemplo, vamos a suponer que se quiere crear un título o cabecera para los resultados, utilizaremos BEGIN para definirlo antes de procesar el contenido del fichero:

Como se puede apreciar, se utiliza BEGIN para definir el título “The file contents:”

 

Post Procesamiento de los datos

Para poder modificar el comportamiento de la salida, una vez ya han sido procesados los datos, se utiliza la palabra clave END.

Por ejemplo, vamos a añadir un footer a la salida de nuestro comando:

Como se aprecia en el ejemplo, se añade el texto “File footer” al final de la salida, y también es posible utilizar ambas (BEGIN y END) a la vez.

 

Utilizando condicionales en AWK

El lenguaje de scripting AWK permite también el uso de condicionales if, else, else if.

Veamos el siguiente ejemplo:

En el anterior ejemplo imprimimos los usuarios que tienen un sueldo mayor de 30000.

Añadamos ahora un else para indicar también los que tienen un sueldo inferior a 30000:

Vemos como nos ha devuelto una salida diferente en función del salario de cada usuario, añadamos como último paso una condición extra utilizando else if:

Vemos como es posible utilizar condicionales en función de lo que necesitamos obtener en cada momento, y como ya se vió, es posible guardar nuestra configuración en fichero para hacer más sencilla la carga de la misma.

 

Uso de bucles en AWK

Bucle while

Es posible también utilizar un bucle while para iterar sobre una condición.

Vámoslo en un ejemplo:

El ciclo se ejecutará y cada vez añadirá 1 a la variable sum hasta que esta sea igual a 4.

Es posible también utilizar la palabra clave break o continue para cortar el bucle:

 

Bucle for

Es posible también utilizar un bucle for para iterar sobre una condición.

Veámoslo en un ejemplo:

Al igual que en el bucle while, también es posible también utilizar la palabra clave break o continue para cortar el bucle.

 

Uso de funciones en AWK

Funciones integradas

Dentro de las funciones integradas en AWK podemos diferencias las mismas en función de si están destinadas a valores numéricos, cadenas de texto o de sistema.

Funciones básicas

En esta parte vamos a ver algunas de las funciones más básicas que se pueden utilizar en awk:

  • print e1, e2, en… -> devuelve los valores de e1, e2, en.
  • printf f, e1, e2, en… -> devuelve los valores de e1, e2, … con el formato especificado en f (por ejemplo “string %s”, $1).
  • getline X -> lee el siguiente registro de entrada y se lo asigna a x, si no se especifica x se asignará a $0.
  • close(f) -> cierra el archivo o pipe abierto con print, printf o getline.
  • system(cmd) -> ejecuta el comando especificado y retorna el estado de la salida de este.

 

Funciones matemáticas

Si te gustan las matemáticas o quieres operar con valores numéricos tienes aqui algunas funciones integradas:

  • sqrt(x) -> devuelve la raíz cuadrada del argumento.
  • log(x) -> devuelve el logaritmo en neperiano del argumento (base e).
  • exp(x) -> devuelve el valor de e elevado al argumento.
  • int(x) -> devuelve la parte entera del argumento.
  • cos(x) -> devuelve el coseno del argumento.
  • sin(x) -> devuelve el seno del argumento.
  • atan(x) -> devuelve el arco tangente del argumento.
  • rand() -> devuelve un número aleatorio comprendido entre 0 y 1.

Veamos un ejemplo devolviendo la parte entera de un valor float:

 

Funciones de string

Existen muchas funciones para el procesado de cadenas de texto, dejamos aqui algunas de ellas:

  • length(x) -> devuelve la longitud del argumento.
  • match(s,r) -> devuelve la posición de s en donde ocurre r, comenzando en 1. Si la cadena no existe devolverá 0.
  • substr(s,m,n) -> devuelve la subcadena de s que comienza con la posición m y finaliza en la posición n.
  • sub(r,t,s) -> sustituye la primera ocurrencia de t por r en la cadena s. Si no se especifica s se tomará todo el registro ($0).
  • gsub(r,t,s) -> igual que sub, pero sustituyendo todas las ocurrencias existentes.
  • split(s,array,sep) -> divide la cadena s en un array. Si no se especifica el valor de sep, se utilizará el valor de FS como separador.
  • index(s1,s2) -> devuelve la posición de la cadena s1 en donde se encuentra la cadena s3. Si no existe devolverá 0.
  • sprintf(f,e1,e2,en) -> devuelve la cadena resultante de imprimir los valores e1, e2, en…  con el formato que se especifique en f.
  • toupper(s) -> devuelve la cadena s convertida a mayúsculas.
  • tolower(s) -> devuelve la cadena s convertida a minúsculas.

 

Veamos un ejemplo de la cadena “welcome” pasada por la función toupper:

 

Funciones creadas por el usuario

Además de utilizar las funciones integradas en awk, también es posible crear funciones personalizadas. Vamos a ver un ejemplo de ello a continuación:

 

Hasta aquí por ahora, espero que les ayude en su día a día y les ayude a familiarizarse con este increíble comando de linux. Y como siempre, cualquier duda, aporte o sugerencia es bienvenida en la sección de comentarios.

 

Deja una respuesta

Tu dirección de correo electrónico no será publicada.