Notas sobre awk

Post image

Una poderosa herramienta para procesar datos

AWK es un lenguaje de programación diseñado para el procesamiento de datos basados en texto. El nombre, según la Wikipedia, procede de las iniciales de sus autores: Alfred Aho, Peter Weinberger y Brian Kernighan (AWK).

Se usa así:

$ awk options program file

awk puede tomar las siguientes opciones:

  • -F (fs) Para especificar un separador de archivos.
  • -f (file) Para especificar un archivo que contenga un script awk.
  • -v (var=value) Para declarar una variable.

Para definir un script awk utilizamos llaves rodeadas por unas comillas simples

$ awk '{print "Welcome to awk command tutorial "}'

Utilizando Variables

Una de la potencia de awk es su capacidad para procesar ficheros de texto.

awk asigna algunas variables para cada campo de datos encontrado:

  • $0 para toda la línea.
  • $1 para el primer campo.
  • $2 para el segundo campo.
  • $n para el campo enésimo campo.

Ejemplo 1: $0

$ awk '{print $0}' test.txt
# salida:
Este es un ejemplo
de texto con
varias
líneas

Ejemplo 2: $1

$ awk '{print $1}' test.txt
# Salida: (sólo imprime la primera palabra de cada línea):
Este
de
varias
líneas

Separador

Es posible que, en determinados casos, el separador no sea ni el espacio ni la tabulación, sino otro u otros caracteres. Se puede especificar con el parámetro – F:

Ejemplo 3: uso de -F (separador)

# En este caso el separador es ":"
$ awk -F: '{print $1}' /etc/passwd
# Salida:

nobody
root
daemon
_uucp
_taskgated
_networkd
_installassistant
_lp
_postfix
_scsd
...

Utilizando múltiples comandos

Para ejecutar múltiples comandos, sepáralos con un símbolo de punto y coma (;) de la siguiente forma:

Ejemplo 4: uso de varios comandos

$ echo "Hola Tom" | awk '{$2="Juan" ; print $0}'
# Salida:
Hola Juan

Leer el script desde un archivo

Escribir el script awk en un archivo y especificarlo utilizando la opción –f:

Contenido del script awk escrito en el fichero testfile:

{print $1 " home at " $6}

Ejemplo 5: ejecutar un script awk escrito en un fichero

$ awk -F: -f testfile /etc/passwd
# salida:
nobody home at /var/empty
root home at /var/root
daemon home at /var/root
_uucp home at /var/spool/uucp
_taskgated home at /var/empty
_networkd home at /var/networkd
...

Problema 1

Tenemos el siguiente fichero de texto:

gonzalez*garcia,pepe;123456789;cl pez, 1 1A;Gijón;Asturias
gonzalez*perez,pepa;999555666;cl pez, 1 1A;Gijón;Asturias
garcia*fernandez,pepito;222333444;cl pez, 1 1A;Gijón;Asturias
garcia*fernandez,pepita;777555444;cl pez, 1 1A;Gijón;Asturias

Y queremos tratarlo para que nos devuelva algo así:

 Encabezado de informe
   - pepe gonzalez garcia vive en cl pez, 1 1A en Gijón (Asturias)
   - pepa gonzález perez vive en cl pez, 1 1A en Gijón (Asturias)
   - pepito garcia fernandez vive en cl pez, 1 1A en Gijón (Asturias)
   - pepita garcia fernandez vive en cl pez, 1 1A en Gijón (Asturias)
---- Fin informe

Pasos a seguir

En primer lugar hemos de separar el nombre de los apellidos. El separador es una coma “,”.

Quedaría así:

  • trozo 1: apellido1*apellido2
  • trozo 2: nombre

En segundo lugar hemos de separar el apellido1 y el apellido2. El separador es un asterisco “*”.

Quedaría así:

  • trozo 1: apellido1
  • trozo 1: apellido2

Solución

awk dispone de la función split que nos viene muy bien para nuestro propósito.

El script awk quedaría así:

# nombres.awk

# funciones para devolver cada uno de los trozos

## Nombre:
## En la matriz arrNombres se depositan los distintos trozos (separados por ",")
## Devuelve el 2º trozo, que es el nombre
function nombre(cadena){
    str = split(cadena, arrNombres, ",")
    return arrNombres[2]
}

## Apellidos:
function apellido1(cadena){
    str = split(cadena, arrNombres, ",")
    ## Primero nos quedamos con el primer elemento (los 2 apellidos)
    ## Después dividimos por (*) con lo cual en b tenemos 2 elementos:
    str1 = split(arrNombres[1],arrApellidos,"*")
    ## b[1] => primer apellido
    return arrApellidos[1]
}

function apellido2(cadena){
    str = split(cadena, arrNombres, ",")
    str1 = split(arrNombres[1],arrApellidos,"*")
    ## b[2] => segundo apellido
    return arrApellidos[2]
}

BEGIN {FS=";" ; OFS="-"; print "Encabezado de informe"}
{print "   - " nombre($1) " " apellido1($1) " " apellido2($1) " vive en " $3 " en "$4 " ("$5")" }
END {print "---- Fin informe"}

Para ejecutar el script:

$ awk -f nombres.awk nombres.csv

[Problema 2]

Con el fichero nombres.csv anterior, crear otro fichero, nombres_cambiados.csv, con los campos separador por “;” y con los campos nombre, apellido1 y apellido2 en columnas separadas.

Solución:

## nombres1.awk

function nombre(cadena){
    str = split(cadena, arrNombres, ",")
    return arrNombres[2]
}

function apellido1(cadena){
    str = split(cadena, arrNombres, ",")
    str1 = split(arrNombres[1],arrApellidos,"*")
    return arrApellidos[1]
}

function apellido2(cadena){
    str = split(cadena, arrNombres, ",")
    str1 = split(arrNombres[1],arrApellidos,"*")
    return arrApellidos[2]
}

BEGIN {FS=";" ; OFS="-"}
{print nombre($1) ";" apellido1($1) ";" apellido2($1) ";" $3 ";" $4 ";" $5 }

Para ejecutarlo:

 $ awk -f nombres1.awk nombres.csv > nombres_cambiados.csv

Resultado:

pepe;gonzalez;garcia;cl pez, 1 1A;Gijón;Asturias
pepa;gonzalez;perez;cl pez, 1 1A;Gijón;Asturias
pepito;garcia;fernandez;cl pez, 1 1A;Gijón;Asturias
pepita;garcia;fernandez;cl pez, 1 1A;Gijón;Asturias

Leer +

También te puede interesar: