---
# System prepended metadata

title: Intro a Awk.
tags: [' Big Data', DAM]

---

---
title: Intro a Awk.
tags: DAM, Big Data
---

<div style="width: 30%; margin-left: auto;">
    
![](https://hackmd.io/_uploads/HJiR4eGJT.png)    
    
</div>



<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Llicència de Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />Aquesta obra està subjecta a una llicència de <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Reconeixement-CompartirIgual 4.0 Internacional de Creative Commons</a>

# Intro a Awk.
![imagen](https://hackmd.io/_uploads/r1UuuvPM0.png)

Quan treballem amb informació emmagatzemada de manera semiestructurada en fitxers de text és molt comú haber de realitzar operacions de preparació i filtratge de les dades prèvies al seu procéssament. 
Si treballem sovint amb el mateix format, és molt útil disposar d'un script de pre-processat que realitzi aquesta tasca de preparació, però si necessitem realizar aquest tipus de tasques una única vegada, normalment és encara més ràpid i pràctic fer ús d'eines standar de processament de dades.
Una opció comuna és l'ús de fulls de càlcul, tot i que no sempre és la més pràctica, però normalment és una eina amb la que molta gent es sent còmoda.
Una molt bona alternativa és utilitzar la comanda de consola '__awk__', o la seva versió GNU: '**gawk**'.

## Què és Awk?
Awk és una utilitat de consola, que es podria arribar a considerar fins i tot un llenguatge de programació orientat al tractament de text. 
Gairabé tots els sistemes operatius existents disposen d'una versió d'awk. Va ser creada a la dècada dels 70's als [laboratoris Bell](https://en.wikipedia.org/wiki/Bell_Labs).

La funció principal d'awk és processar fitxers de text línia per línia, buscant patrons específics i executant accions determinades quan aquests patrons són trobats. És especialment útil per a tasques com extracció de dades, transformació de formats, generació de informes, etc.

El funcionament bàsic d'awk es basa en regles. Cada regla consisteix en un patró i una acció associada. 

> patrò {acció}

L'awk llegeix el fitxer de text línia per línia i compara cada línia amb els patrons definits a les regles. Quan troba una coincidència, executa l'acció associada a aquest patró.

Per exemple, una regla senzilla podria ser:
```bash=
awk '1 { print }' fitxer_de_text
```
L'exemple anterior és bàsicament inútil, però il·lustra el funcionament i la sintaxi de les regles awk. 
  '1' és una constant amb valor diferent de zero.
  { print } és l'acció a realitzar, que per una altra banda, print és també l'acció per defecte a realitzar quan no s'especifica una acció.
  
Per tant, el nostre exemple recorrerà tot el fitxer de text línia per línia i el mostrarà per pantalla.

## Exemples d'ús.
Podem trobar una bona explicació amb exemples d'ús al següent link: [https://linuxhandbook.com/awk-command-tutorial/](https://linuxhandbook.com/awk-command-tutorial/)

## Fitxer d'exemple

```=
DNI#APE_1#APE_2#NOM#DIA#MES#ANO#F_NAC#EDAD#DEPART#C_CONDUCIR#N_HIJOS#ESTADO_CIVIL#SUELDO
45.302.157-T#HAANAN#MIMUN#NADIA#7#1#1990#32880#26#INFORMATICA#NO#5#DIVORCIADO#1743
43.094.614-R#ABAD#BARRIO#FUENCISLA#9#8#1968#25059#47#SERVICIO TÉCNICO#NO#2#SOLTERO#2044
32.843.994-V#ABAD#VÁZQUEZ#TATIANA PALOMA#10#1#1962#22656#54#INFORMATICA#SI#1#SOLTERO#2774
13.138.768-H#ABAJO#HERNANDO#INMACULADA#26#9#1957#21089#58#RRHH#NO#5#SOLTERO#912
71.555.763-A#ABANADES#FERNÁNDEZ#LIBERTAD#16#11#1989#32828#26#RRHH#NO#2#SOLTERO#2095
45.293.901-R#ABDELKADER#MIMUN#KARIMA#7#11#1985#31358#30#SERVICIO TÉCNICO#NO#2#DIVORCIADO#2243
45.283.008-X#ABDEL-LAH#MOHAMED#CANDILA#23#3#1983#30398#32#CONTABILIDAD#SI#4#SOLTERO#2026
45.281.108-L#ABDERRAMAN#MOHAMED#LEILA#10#8#1982#30173#33#I+D#NO#2#DIVORCIADO#2520
12.383.679-L#ABRIL#FERNÁNDEZ#ELENA#21#10#1936#13444#79#RRHH#SI#5#CASADO#2488
71.547.481-R#ACEDO#PEREZ#ADORALINA#20#5#1959#19499#62#RRHH#SI#3#DIVORCIADO#1413
45.282.525-X#ACOSTA#BERNABE#M. ANGELES#24#10#1035#13081#80#INVESTIGACIÓN#NO#1#VIUDO#1555
80.159.645-E#ACOSTA#FERNÁNDEZ#MARIA#5#2#1947#17203#69#INVESTIGACIÓN#NO#1#SOLTERO#2066
51.929.697-K#ACOSTA#GONZALEZ#M. CARMEN#7#11#1977#28436#38#I+D#SI#1#SOLTERO#3049
06.243.735-V#ADEVA#RODRÍGUEZ#AFRICA#1#11#1936#13455#79#RRHH#NO#3#CASADO#973
53.567.648-G#AGRO-MARTÍN#JUAREZ#LUZDIVINA#21#11#1955#20414#60#RRHH#NO#3#DIVORCIADO#2666
12.760.394-V#AGUADO#SAN MARTÍN#JUAN CARLOS#11#7#1970#25760#45#CONTABILIDAD#SI#5#SOLTERO#2690
46.451.841-Y#AGUAYO#FERRERAS#DAMARIS#22#10#1980#29516#35#RRHH#NO#4#VIUDO#1303
44.097.101-Y#AGUDELO#LONDOÑO#NEILA ESLEIDI#27#3#1954#19810#61#RRHH#NO#5#SOLTERO#1778
```

## Ús de variables.
Awk permet l'ús de variables per a emmagatzemar dades. Les variables no necessiten ser declarades, i el tipus s'infereix directament del valor que hi assignem.
```awk=
variable_numerica = 10;
variable_text = "Hola, món!";
```
Totes les variables a Awk tenen un àmbit global i són accessibles des de qualsevol part de l'script.

### Variables pròpies d'Awk.
Awk té un conjunt de variables predefinides:
* __RS__ [separador de registres / **R**ecord **S**eparator]: Per defecte és el separador de línia, però el podem canviar per qualsevol altre caracter.
* __FS__ [separador de camps / **F**ield **S**eparator]: Awk utilitza l'espai en blanc com a separador de camps per defecte.
* __OFS__ [separador de camps a la sortida / **O**utput **F**ield **S**eparator]: És el caracter que utilitzarà Awk per separar els diferents camps quan els imprimeis per la sortida.
* __NF__ [nombre de camps / **N**umber of **F**ields]: El nombre de camps que conté el registre actual. Si el separador és l'espai en blanc coincidirà amb el nombre de paraules de la línia actual.
* __NR__ [posició del registre actual /**N**umber of **R**ecord]: Si mantenim el separador de registres per defecte, coincideix amb el nombre de la línia actual.

### Exemple d'ús de variables.
1. Comptar les paraules d'un fitxer de text: 
```text=
La casa que vull,
que la mar la vegi
i uns arbres amb fruit
que me la festegin.

Que hi dugui un camí
lluent de rosada,
no molt lluny dels pins
que la pluja amainen.

Per si em cal repòs
que la lluna hi vingui;
i quan surti el sol
que el bon dia em digui.

Que al temps de l’estiu
niui l’oreneta
al blanc de calç ric
del porxo amb abelles.

Oint la cançó
del pagès que cava;
amb la salabror
de la marinada.

Que es guaiti ciutat
des de la finestra,
i es sentin els clams
de guerra o de festa:
per ser-hi tot prest
si arriba una gesta.
```
```bash=
xavi@portatil:~$ awk ' { paraules += NF } END { print "Nombre de paraules:", paraules  } ' lacasaquevull.txt 
Nombre de paraules: 111

```
2. Comptar el nombre de línies d'un fitxer de text:
```bash=
xavi@portatil:~$ awk ' END { print "Nombre de línies:", NR  } ' lacasaquevull.txt 
Nombre de línies: 31
```
3. Comptar el nombre de paraules de cada línia i el nombre de paraules total:
```bash=
xavi@portatil:~$ awk ' { paraules += NF; print NR, ":", NF} END { print "Nombre de paraules:", paraules  } ' lacasaquevull.txt 
1 : 4
2 : 5
3 : 5
4 : 4
5 : 0
...
26 : 4
27 : 4
28 : 5
29 : 5
30 : 4
31 : 4
Nombre de paraules: 111
```

## Estructures de control.
Awk també permet l'ús d'estructures de control: condicionals i bucles.
### Condicionals.
La sintaxi dels condicionals és:
> if (condició) {instruccions si True} else {instruccions si False}

### Bucles.
Awk incorpora els bucles, __for__ i __while__ com a estructures de control amb la següent sintaxi:
#### Bucle for
La sintaxi del bucle for és similara la que utilitzem amb Java:
```C=
for (inicializacio; condicio; increment/decrement)
   accio
```
##### exemple:
```bash=
$ awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }'
1
2
3
4
5
```
#### Bucle while:
```C=
do
   action
while (condition)
```
##### exemple:
```bash=
$ awk 'BEGIN {i = 1; do { print i; ++i } while (i < 6) }'
1
2
3
4
5
```

### Arrays
Awk anomena __array__ el que en PHP diem __associative array__ o en Python __dictionary__. 
Aquest tipus d'estructura no és una sèrie ordenada d'elements, és un conjunt de parelles clau-valor, i a Awk té la restricció de que la clau sempre ha de ser una cadena de text.
Per recòrrer tots els elements d'un array podem utilitzar un bucle for amb la següent sintaxi:
```=
for (var in arrayname)
actions
```
Imaginem que tenim un log d'un proxy web organitzat en 4 columnes: data, hora, adreça IP i nombre de pàgines web a les que ha accedit cada IP:
```bash=
$ cat Iplogs.txt
180607 093423	123.12.23.122 133
180607 121234	125.25.45.221 153
190607 084849   202.178.23.4 44
190607 084859   164.78.22.64 12
200607 012312	202.188.3.2 13
210607 084849   202.178.23.4 34
210607 121435	202.178.23.4 32
210607 132423	202.188.3.2 167
```
Com podem veure cada IP pot aparèixer més d'una vegada dins del nostre log. Podem utilitzar __awk__ per a comptar quantes vegades apareix cada IP:
```bash=
$ awk '{
> Ip[$3]++;
> }
> END{
> for (var in Ip)
> print var, "access", Ip[var]," times"
> }
> ' Iplogs.txt
```

```=
164.78.22.64 access 1 times
123.12.23.122 access 1 times
202.178.23.4 access 3 times
202.188.3.2 access 2 times
125.25.45.221 access 1 times
```
Podem complicar una mica més l'exemple mostrat a dalt per a indicar també el nombre total de pàgines web a les que accedeix cada màquina. En aquesta ocasió he desat les regles awk en un script anomenat _'script.awk'_ per a poder-lo reaprofitar en ocasions posteriors:
```bash=
$cat script.awk
BEGIN {
print "IP Address\tAccess Count\tNumber of sites";
}
{
Ip[$3]++;
count[$3]+=$NF;
}
END{
for (var in Ip)
	print var,"\t",Ip[var],"\t\t",count[var];
}

$ awk -f script.awk Iplogs.txt
IP Address	Access Count	Number of sites
164.78.22.64 	 1 		 12
123.12.23.122 	 1 		 133
202.178.23.4 	 3 		 110
202.188.3.2 	 2 		 180
125.25.45.221 	 1 		 153
```
### Bones pràctiques

* Defineix sempre el separador de camps (-F) si el fitxer no està separat per espais.
* Usa BEGIN per inicialitzar encapçalaments o variables.
* Usa END per fer resums o informes finals.
* Desa scripts awk en fitxers .awk per reutilitzar-los.
* Prova expressions amb dades simples abans d’aplicar-les a fitxers grans.

### Resum ràpid de sintaxi
|Objectiu|	Comanda|
|---|---|
| Mostrar 2a columna	| awk '{print $2}' fitxer| 
| Filtrar línies amb “ERROR”	| awk '/ERROR/' fitxer| 
| Comptar línies	| awk 'END{print NR}' fitxer| 
| Sumar columna 3	| awk '{sum+=$3} END{print sum}' fitxer| 
| Canviar separador	| awk -F"," '{print $1,$2}' fitxer.csv| 

### Opcions de línia de comandes útils
 |Opció |	Descripció |
 |---|---|
 |-F |	Defineix separador de camps |
 |-v var=value |	Defineix variables abans d’executar Awk |
 |-f script.awk |	Executa un script |
 |--dump-variables |	Mostra variables internes (GNU awk) |
 |--lint |	Comprova errors d’estil o compatibilitat |
 
 