La storia di AWK è lunga, in termini informatici lunghissima. E’ il 1977 quando Alfred Aho, Peter Weinberger e Brian Kerningham (dalle iniziali dei tre il suo nome) presentano questo anomalo linguaggio interpretato, utilissimo per processare files di testo strutturati e generare report.
AWK è un più di un semplice tool e forse qualcosa meno di un completo linguaggio di programmazione, nel senso moderno del termine (anche se è un completo linguaggio di programmazione). Mostra la sua piacevolezza e potenza come filtro in una pipeline, dove si fa preferire alla criptica sintassi di SED e consente di evitare di scomodare il Perl.
AWK, nelle sue varianti (la più diffusa è quella a cura della Free Software Foundation, GAWK) è disponibile praticamente per qualsiasi sistema operativo possiate immaginare. Sì, anche il DOS.
Ma cosa rende insieme unico, attraente e insieme così poco conosciuto questo strumento che ha per logo un simpatico pinguino, 14 anni prima di Linux?
Per spiegarlo inizierò dal concetto di base su cui, a mio avviso, si fonda la corretta comprensione del linguaggio. No, non è un esempio di “Hello World”…
La logica di AWK è semplice, ma potente. Come quasi tutti gli strumenti nati in ambito UNIX, AWK ragiona in termini di linee di testo. Processa una linea alla volta applicando delle regole, composte da:
pattern {azione} sia il pattern che l’azione sono opzionali.
Se manca il pattern, l’azione viene applicata a tutti i record.
Se a mancare è l’azione, il record che corrisponde al pattern è scritto sullo standard output (quindi di default sullo schermo).
Quello che AWK fa, in pratica, è leggere il testo una riga alla volta, separarlo in campi definiti da un delimitatore (modificabile), assegnare i valori a delle variabili predefinite ($1,$2,$3…) e applicare le regole indicate dal programmatore.
AWK può ricevere il testo da processare attraverso una pipe, oppure può presentarsi sotto forma di script, invocabile con awk -f nomescript.awk e processare il file o i files indicato/i.
Complicato? Un esempio mostrerà tutta la semplicità del linguaggio.
Immaginiamo di avere un file di testo chiamato amici.txt:
Aldo, 23 Carlo, 28 Mario, 35 Piero, 17 Stefano, 30 Umberto, 29
Ok, l’esempio è senza senso, ma serve solo per illustrare l’utilizzo di AWK…
se io passo l’output di cat amici.txt tramite una pipe ad AWK in questo modo:
cat amici.txt | awk '/Stefano/ {print $2}' oppure processo amici.txt direttamente così:
awk '/Stefano/ { print $2 }' amici.txt il risultato a schermo sarà… 30
Ricordate? pattern e azione. Se e quando AWK trova “Stefano” stampa il secondo campo, cioè il numero 30. La virgola è il delimitatore di default di AWK. Se avessi avuto come delimitatore il punto e virgola avrei potuto scrivere:
cat amici.txt | awk -F; "/Stefano/ {print $2}" Giochiamo un po’… se avessi scritto:
cat amici.txt | awk "/Stefano/ {print $2, $1}" il risultato sarebbe stato:
30, Stefano
iniziate a capire l’utilità di questo strumento, ad esempio per processare al volo files csv?
un po’ di esempi banalissimi:
{print $1} stampa il primo campo di ogni linea di un file
/pippo/ stampa tutte le linee che contengono pippo
lenght($0) < 40 stampa tutte le linee che contengono meno di 40 caratteri e via dicendo…
Come dicevo, posso usare AWK in una pipe, ma posso anche scrivere dei veri e propri programmi, di maggiore complessità.
Un programma AWK consta di tre parti: le assegnazioni e le operazioni per così dire preliminari, tipo l’assegnazione di variabili globali, che troveranno posto qui:
BEGIN {
...
} (ovviamente questa sezione è del tutto opzionale)
poi seguiranno le istruzioni secondo la logica /pattern/ {azione} che abbiamo già visto.
I pattern possono essere combinati con gli operatori booleani || (OR), && (AND) e ! (NOT).
Le azioni consistono di uno o più comandi, funzioni o assegnazione di variabili, separate da a capo o da punti e virgola e contenute dentro le parentesi graffe {}.
I comandi possono essere assegnazione di variabili (o array), comandi di stampa, funzioni interne, comandi per controllare il flusso dell’operazione.
e per finire, anch’esso opzionale:
END {
...
} dove andrò, ad esempio, a stampare il risultato finale di una mia elaborazione (potrei aver sommato tutti i valori presenti in $2 di tutte le righe in una variabile e dentro END andrò a stampare, alla fine, il valore totale di quella variabile…).
Se salvo il mio script con un nome, ad esempio pippo.awk, posso eseguirlo con:
awk -f pippo.awk
o più comodamente iniziando il mio script con:
#!/usr/bin/awk -f
e poi rendendolo eseguibile.
Le variabili possono essere assegnate nel modo più semplice possibile:
PIPPO = “dsajsakdsk”
Gli arrays possono essere creati con la funzione split:
split (stringa,array[,separatore])
…il resto lo lascio alla vostra fantasia!
Il 21 gennaio 2015 Optimizely — una delle piattaforme di A/B testing più usate al…
Nell'aeronautica militare israeliana, racconta Daniel Kahneman, gli istruttori erano convinti di una cosa: lodare un…
Chi guarda i dati di un sito lo fa di continuo, spesso senza nemmeno accorgersene,…
Abbiamo chiuso l'articolo sul calcolatore di significatività con una promessa. Dicevamo che il p-value risponde…
Il nostro A/B test è arrivato alla fine: la variante B mostra un tasso di…
C'è una domanda che torna, puntuale, ogni volta che pubblico un articolo di questo percorso:…