Curso de AWK (David Barreto)

44
1 08/03/15 Ing. David Barreto Llano (david-barreto.com) Introducción al Lenguaje de Programación AWK

Transcript of Curso de AWK (David Barreto)

108/03/15Ing. David Barreto Llano (david-barreto.com)

Introducción al Lenguaje de Programación AWK

208/03/15Ing. David Barreto Llano (david-barreto.com)

Características del Lenguaje

Lenguaje de programación orientado a datos

Basado en la detección de patrones en los datos por medio de expresiones regulares

Es un lenguaje muy simple que no permite la creación de clases u objetos

Solo implementa variables, arreglos asociativos y estructuras de control

Ideal para el procesamiento de logs

Liviano, rápido e integrado con el shell de Linux

Tiene un set limitado de funciones predefinidas

308/03/15Ing. David Barreto Llano (david-barreto.com)

Historia de AWK

AWK fue Creado en 1977 en “AT&T Bell Laboratories”

El nombre del lenguaje son las siglas de los apellidos de sus creadores: Aho, Weinberger y Kernighan

En 1985 se crea una nueva versión del lenguaje y se bautiza como NAWK (New AWK)

Entre 1986 y 1989, un equipo de voluntarios, con ayuda de Richard Stallman (fundador del movimiento del software libre) crea una versión libre de NAWK pero más potente y es llamado GAWK (GNU AWK)

408/03/15Ing. David Barreto Llano (david-barreto.com)

Las diferentes versiones de AWK

Algunos sistemas mantienen AWK y NAWK como programas independientes

Algunos sistemas han renombrado AWK como OAWK (Old AWK) e internamente redireccionan AWK hacia NAWK o hacia GAWK

Algunos sistemas mantiene de forma independiente todas las versiones del lenguaje: AWK, NAWK y GAWK

El sistema operativo Canaima trae la versión AWK redireccionado a NAWK. Canaima no trae de forma nativa GAWK

Para instalar GAWK en Canaima: sudo apt-get install gawk

Para instalar GAWK en Windows: (Google) GAWK for Widows

508/03/15Ing. David Barreto Llano (david-barreto.com)

¿Cómo determinar la versión de AWK?

$> man awk

608/03/15Ing. David Barreto Llano (david-barreto.com)

Estructura Básica

Un programa AWK consta de un conjunto de reglas, que buscan patrones sobre los archivos de entrada y ejecuta acciones si encuentra una coincidencia

$1 == "abc" || $2 > 30 { suma = $1+$2+5 print(suma)}

Patrón

Regla

Acción

708/03/15Ing. David Barreto Llano (david-barreto.com)

Estructura Básica

Los campos de cada entrada se acceden usando números precedidos por el símbolo de dólar

$1 = Accede al primer campo de la entrada

$2 = Accede al segundo campo de la entrada

$N = Accede al enésimo campo de la entrada (N={1,2,3,..})

$0 = Accede a toda la entrada

Si se trata de acceder a un campo inexistente AWK retorna un string vacío

808/03/15Ing. David Barreto Llano (david-barreto.com)

Estructura Básica

Existen reglas especiales que se ejecutan una sola vez al inicio (BEGIN) y al final (END)

Si se omite el patrón de una regla, la acción se ejecuta siempre para todas las entradas

Si se omite la acción, no se realiza ninguna operación

Las reglas se ejecutan en el mismo orden en que son definidas

908/03/15Ing. David Barreto Llano (david-barreto.com)

Estructura Básica

Los campos de cada entrada se acceden usando números precedidos por el símbolo de dólar

$1 = Accede al primer campo de la entrada

$2 = Accede al segundo campo de la entrada

$N = Accede al enésimo campo de la entrada (N={1,2,3,..})

$0 = Accede a toda la entrada

Si se trata de acceder a un campo inexistente AWK retorna un string vacío

1008/03/15Ing. David Barreto Llano (david-barreto.com)

Ejemplos de Uso

$2 == "Oriente" { print($1)}

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

Albany

$2 == "Caracas" { print($1)}$1 == "Gabriela" { print($2)}

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

DavidOccidente

BEGIN { print("Inicio") }{ print($2) }END { print("Fin") }

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

InicioCaracasOccidenteCentroOrienteFin

1108/03/15Ing. David Barreto Llano (david-barreto.com)

Ejecutar BEGIN

Leer próxima entrada

Validar el patrón en la entrada ¿Hay coincidencia?

¿Fin del archivo?

Ejecutar END

Ejecutar acción

Algoritmo de ejecución de AWK (resumen)

NONO

SI

SI

1208/03/15Ing. David Barreto Llano (david-barreto.com)

Formas de Ejecutar de AWK

Desde la línea de comandos

gawk '{ print($1) }' optimizacion_v2.txt

Desde la linea de comandos usado como parte de un “pipe” del shell

cat optimizacion_v2.txt | gawk '{ print($1) }'

Desde un archivo

gawk -f procesador.awk optimizacion_v2.txt

gawk -f procesador.awk optimizacion_v2.txt > resultado.txt

1308/03/15Ing. David Barreto Llano (david-barreto.com)

David Barreto, (0416) 629-0508, CaracasDavid Mercado, (0416) 613-4416, OrienteJerald Almeida, (0212) 705-7456, CaracasVíctor Prieto, (0426) 896-7706, Centro

optimizacion_v1.txt

procesador.awk

{ print($1) }

{ print($1, $4) }

BEGIN { FS = "," }{ print($1, $3) }

BEGIN { FS = "," OFS = ";"}{ print($1, $3) }

BEGIN { FS = "," OFS = ";"}$3 == "Caracas" { print($1, $3) }

BEGIN { FS = "," OFS = ";"}$3 == " Caracas" { print($1, $3) }

BEGIN { FS = ", " OFS = ";"}$3 == "Caracas" { print($1, $3) }

BEGIN { FS = ", " OFS = ";"}$1 ~ /David/ { print("David de " $3) }

gawk -f procesador.awk optimizacion_v1.txt

¿Qué resultado genera cada uno de estas variantes del archivo "procesador.awk"?

1408/03/15Ing. David Barreto Llano (david-barreto.com)

Comentarios en el Código

Los comentarios son líneas de texto dentro del código que son ignoradas por el interpretador

Funcionan como referencias documentales para el programador

En AWK los comentarios se inician con el símbolo "#"

No existe un símbolo de comentario multilínea

# Compara el campo 1 con el valor 5# e indica si hay match$1 == 5 { print("match!") # Texto de referencia}

1508/03/15Ing. David Barreto Llano (david-barreto.com)

Función interna del lenguaje "print"

Imprime resultados en la consola o en un archivo de salida e inserta un salto de línea (\n) al final

{ print($1) }

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

DavidGabrielaJonathanAlbany{ print $1 }

{ print($1, $2) }

{ print("Hola " $1) }

Hola DavidHola GabrielaHola JonathanHola Albany

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

optimizacion_v2.txt

1608/03/15Ing. David Barreto Llano (david-barreto.com)

Estructuras de control

Estructura if-else

Estructura for

if(power > 15) {print("BTS de alta potencia")

} else {print("BTS de baja potencia")

}

for(i=0; i<5; i++) {print(i)

}

1708/03/15Ing. David Barreto Llano (david-barreto.com)

Arreglos

AWK tiene un manejo muy básico de los arreglos

En AWK todos los arreglos son asociativos

No hay forma de inicializar un arreglo con valores

celdas[88] = "Catia"celdas[140] = "Altamira"celdas["23"] = "San Martín"celdas["Modcell"] = 1

#Esto no es válido...frutas = ["fresa", "mora", "piña"]

#Esto si es válido...frutas[0] = "fresa"frutas[1] = "mora"frutas[2] = "piña"

1808/03/15Ing. David Barreto Llano (david-barreto.com)

Arreglos

Operaciones básicas

Buscar un índice dentro de un arreglo

#Asignación de valores a un arreglocapitales["Venezuela"] = "Caracas"capitales["Colombia"] = "Bogotá"

#Lectura de valores de un arregloprint(capitales["Venezuela"])

#Eliminación de valores de un arreglodelete capitales["Venezuela"]

if("Colombia" in capitales) { print("Colombia es un índice del arreglo")} else {

print("Colombia no es un índice del arreglo")}

1908/03/15Ing. David Barreto Llano (david-barreto.com)

Arreglos

Recorrer todos los elementos de un arreglo

Buscar un valor dentro de un arreglo

for(i in capitales) { print(capitales[i])}

found = 0for(capital in capitales) {

if(capitales[capital] == "Caracas") {found = 1break

}}if(found) {

print("Caracas es un valor del arreglo")}

2008/03/15Ing. David Barreto Llano (david-barreto.com)

Arreglos: Consideraciones Especiales

Para emular una inicialización de un arreglo en una sola línea, se debe hacer uso de la función split

Cuando se hace referencia a un elemento del arreglo que no existe, AWK automáticamente le asigna el valor del string vacío

split("fresa mora piña", frutas, " ")

capitales["Venezuela"] = "Caracas"capitales["Colombia"] = "Bogotá"

#En otros lenguajes esto daría un errorcap_ecuador = capitales["Ecuador"] #cap_ecuador == ""

2108/03/15Ing. David Barreto Llano (david-barreto.com)

Función interna del lenguaje "printf"

Similar a print pero permite un mayor control del formato

No inserta de forma automática un salto de línea al final

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

{ printf("%s pertenece a %s\n", $1, $2) }

David pertenece a CaracasGabriela pertenece a OccidenteJonathan pertenece a CentroAlbany pertenece a Oriente

2208/03/15Ing. David Barreto Llano (david-barreto.com)

Letras de control de formato

%i, %d: Imprime números enteros (integers)

%s: Imprime cadenas de texto (strings)

%f: Imprime valores de punto flotante (floats)

awk 'BEGIN{printf("%i %s tienen %f bolívares\n",5,"personas",2500)}'

5 personas tienen 2500.000000 bolívares

2308/03/15Ing. David Barreto Llano (david-barreto.com)

Modificadores del formato

Posición (N$): Permite usar variables por posición

Precisión (.N): Indica la cantidad de decimales para imprimir

gawk 'BEGIN{printf("%1$s: CELL %1$s; SECTOR %2$i\n", "00981", 2)}'

00981: CELL 00981; SECTOR 2

gawk 'BEGIN{printf("En la cuenta hay %.2f bolívares\n", 7800)}'

En la cuenta hay 7800.00 bolívares

2408/03/15Ing. David Barreto Llano (david-barreto.com)

Redireccionamiento de la Salida

Por default, la salida de AWK (print, printf) va directamente a la consola

El redireccionamiento de la salida se puede definir desde el comando de invocación o dentro del propio código

awk 'BEGIN{print("hola")}' > salida.txt

BEGIN { print("hola") > "salida.txt"}

2508/03/15Ing. David Barreto Llano (david-barreto.com)

Redireccionamiento de la Salida

Dentro del código, existen dos formas de redireccionamiento: borrar y agregar (>) o solo agregar (>>)

#Si salida.txt no existe, AWK lo crea automáticamenteBEGIN { print("hola") > "salida.txt" #Borra el contenido primero

print("chao") > "salida.txt" #Agrega la información}

#Si salida.txt no existe, AWK lo crea automáticamenteBEGIN { print("hola") >> "salida.txt" #Agrega la información

print("chao") >> "salida.txt" #Agrega la información}

2608/03/15Ing. David Barreto Llano (david-barreto.com)

Variables Predefinidas

FS (Field Separator): Separador de campo de entrada

OFS (Output Field Separator): Separador de campo de salida

RS (Record Separator): Separador de fila de entrada

ORS (Output Record Separator): Separador de fila de salida

NF (Number of Fields): Cantidad de campos de la fila actual

NR (Number of Records): Cantidad de filas del archivo

FNR (actual Record Number): Número de la fila actual

2708/03/15Ing. David Barreto Llano (david-barreto.com)

FS: Separador de Campo de Entrada

Define el caracter o conjunto de caracteres que serán usados para la separación de los campos de una "entrada"

BEGIN { FS = ";"}{ print($2) }

David; CaracasGabriela; OccidenteJonathan; CentroAlbany; Oriente

Caracas Occidente Centro Oriente

BEGIN { FS = "..."}{ print($2) }

David...CaracasGabriela...OccidenteJonathan...CentroAlbany...Oriente

CaracasOccidenteCentroOriente

optimizacion_v2.txt

2808/03/15Ing. David Barreto Llano (david-barreto.com)

FS: Separador de Campo de Entrada

Su valor por defecto es el caracter vacío (" "). Este es un caso especial que incluye cualquier cantidad de espacios consecutivos o tabulaciones (\t)

Ignora los espacios en blanco al inicio o al final de la entrada

{ print($2) }

David Caracas Gabriela OccidenteJonathan Centro Albany Oriente

CaracasOccidenteCentroOriente

{ print($2) }

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

CaracasOccidenteCentroOriente

2908/03/15Ing. David Barreto Llano (david-barreto.com)

FS: Separador de Campo de Entrada

El separador de campo puede ser definido como una expresión regular

BEGIN { FS = "--[abcd]--"}{ print($2) }

David--a--CaracasGabriela--b--OccidenteJonathan--c--CentroAlbany--d--Oriente

CaracasOccidenteCentroOriente

BEGIN { FS = "(=)+"}{ print($2) }

David======CaracasGabriela===OccidenteJonathan===CentroAlbany=====Oriente

CaracasOccidenteCentroOriente

3008/03/15Ing. David Barreto Llano (david-barreto.com)

FS: Separador de Campo de Entrada

Si se usa el string vacío ("") como separador de campo, cada caracter de la entrada se convierte en un campo independiente

BEGIN { FS = ""}{ print($2) }

David; CaracasGabriela; OccidenteJonathan; CentroAlbany; Oriente

aaol

3108/03/15Ing. David Barreto Llano (david-barreto.com)

OFS: Separador de Campo de Salida

Define el o los caracteres de separación de los campos, al momento de "imprimir" resultados en la consola o en un archivo de texto

BEGIN { FS = "--" OFS = "; "}{ print($1, $2) }

David--CaracasGabriela--OccidenteJonathan--CentroAlbany --Oriente

David; CaracasGabriela; OccidenteJonathan; CentroAlbany; Oriente

BEGIN { FS = "--" OFS = "; "}{ $1 = $1 print($0)}

David--CaracasGabriela--OccidenteJonathan--CentroAlbany --Oriente

David; CaracasGabriela; OccidenteJonathan; CentroAlbany; Oriente

3208/03/15Ing. David Barreto Llano (david-barreto.com)

NF: Número de campos de la entrada

El campo NF es una variable propia del lenguaje que nos informa cuantos campos hay por entrada

Se define automáticamente para cada entrada procesada

Es usado para acceder al último (penúltimo, antepenúltimo, etc.) elemento de una entrada

{ print(NF) }a b c dx y3 2 5

423

{ print($NF) }a b c dx y3 2 5

dy5

{ print($(NF-1)) }a b c dx y3 2 5

cx2

random_v1.txt

3308/03/15Ing. David Barreto Llano (david-barreto.com)

El Campo $0: Impresión con separador

Cuando se imprime el campo $0, se imprime la entrada completa igual a como aparece en la fuente

Para imprimir la entrada con el nuevo caracter se separación (OFS), se debe primero realizar una asignación "dummy"

BEGIN { OFS = ", "}{ print($0) }

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

BEGIN { OFS = ", "}{ $1 = $1 print($0)}

David CaracasGabriela OccidenteJonathan CentroAlbany Oriente

David, CaracasGabriela, OccidenteJonathan, CentroAlbany, Oriente

3408/03/15Ing. David Barreto Llano (david-barreto.com)

Valores Booleanos

AWK no implementa las constantes True o False como la mayoría de los lenguajes para definir valores booleanos

En su lugar, AWK toma el valor 0 y el string vacío como False y cualquier otro valor como True

Las expresiones lógicas en AWK retornan 1 (True) ó 0 (False)

if(5 == 5) # 1 (True)

if("Juan") # 1 (True)

if(34567) # 1 (True)

if(0) # 0 (False)

if("") # 0 (False)

3508/03/15Ing. David Barreto Llano (david-barreto.com)

Operadores Lógicos

Operador AND: Ambas condiciones deben cumplirse

Operador OR: Al menos una condición debe cumplirse

Operador NOT: Negación de la expresión

(5 >= 3) && (4 < 6)(5 >= 6) && (4 < 6)

(5 >= 3) || (4 == 3)(5 >= 5) || (4 <= 5)

!(3 == 3) || !(2 > 1)!((3 > 4) && (5 == 3))

# 1 (True)# 0 (False)

# 1 (True)# 1 (True)

# 0 (False) # 1 (True)

3608/03/15Ing. David Barreto Llano (david-barreto.com)

Patrones Combinados

Bolígrafo 30 64.99Lápiz 80 15.50Borrador 0 8.75Libro 0 350.00Cuaderno 12 199.99Libreta 19 235.00

$1 ~ /^L/ && $3 > 30 { print($0)}

$1 == "Lápiz" || $1 == "Borrador" { print($0)}

$3 >= 30 && $3 <= 100 { print($0)}

($1 ~ /[Bb]/ && $2 > 0) || $3 <= 20 { print($0)}

inventario.txt

3708/03/15Ing. David Barreto Llano (david-barreto.com)

Expresiones Regulares

Una expresión regular es un conjunto de símbolos que permiten realizar una búsqueda por patrones de texto

Las expresiones regulares usualmente están demarcadas entre símbolos de slash (/)

/uan/

El operador de coincidencia es el símbolo ~

$1 ~ /uan/ { … }

Se puede aplicar el operador de negación sobre el operador de coincidencia !~

$1 !~ /uan/ { … }

AWK permite usar expresiones regulares para definir variables del lenguaje como FS y RS

3808/03/15Ing. David Barreto Llano (david-barreto.com)

Ejemplos de Expresiones Regulares

Buscar las palabras que contengan la secuencia "in"

Buscar las palabras que empiecen por "L"

LisoLinoPinolimón512

$1 ~ /in/ { print($1)}

LinoPino

LisoLinoPinolimón512

$1 ~ /^L/ { print($1)}

LisoLino

random_v2.txt

3908/03/15Ing. David Barreto Llano (david-barreto.com)

Ejemplos de Expresiones Regulares

Buscar las palabras que empiecen por "L" o "l"

Buscar las palabras que terminen con "no"

LisoLinoPinolimón512

$1 ~ /^[Ll]/ { print($1)}

LisoLinolimón

LisoLinoPinolimón512

$1 ~ /no$/ { print($1)}

LinoPino

4008/03/15Ing. David Barreto Llano (david-barreto.com)

Expresiones Regulares

Buscar las "palabras" que consten exclusivamente de números

Buscar las palabras contengan una secuencia que inicia con "i", seguida de cualquier letra, seguida de la letra "o"

LisoLinoPinolimón512

$1 ~ /^[0-9]$/ { print($1)}

512

LisoLinoPinolimón512

$1 ~ /i.o/ { print($1)}

LisoLinoPino

4108/03/15Ing. David Barreto Llano (david-barreto.com)

Expresiones Regulares

Buscar las "palabras" que contengan una secuencia que inicie con 1 y tenga al menos un 8 a continuación

Buscar las "palabras" que contengan una secuencia que inicie con 1 y tenga cero, uno o varios 8 a continuación

18921889219888881982

$1 ~ /1(8)+/ { print($1)}

18921889

18921889219888881982

$1 ~ /1(8)*/ { print($1)}

1892188921981982

4208/03/15Ing. David Barreto Llano (david-barreto.com)

Expresiones Regulares

Buscar las "palabras" que contengan una secuencia que inicie con 1 y tenga al menos dos 8 a continuación

Buscar las "palabras" que contengan una secuencia que tenga entre 2 y 4 números ocho consecutivos

18921889219888881982

$1 ~ /1(8){2,}/ { print($1)}

21889

18921889219888881982

$1 ~ /(8){2,4}/ { print($1)}

218898888

4308/03/15Ing. David Barreto Llano (david-barreto.com)

Funciones

Las funciones son bloques de código reutilizables

function comando_btseqp(bts, potencia) { printf("BTS: %s - Power: %0.f", bts, potencia)}

$2 == 507 { comando_btseqp($1, $3)}

4408/03/15Ing. David Barreto Llano (david-barreto.com)

Funciones

Las funciones en AWK pueden definirse en cualquier parte del código fuente

Si se invoca una función sin definir uno o más parámetros, estos adquieren automáticamente el valor del string vacío

Dentro de una función no es posible definir variables locales. Para ello, se definene parámetros para los cuales nunca se le asignan argumentos

function comando(bts, potencia, i) { i = 3 printf("%i) BTS: %s - Power: %0.f", i, bts, potencia)}

2 == 507 { i = 2 comando_btseqp($1, $3) print(i)}