C.2. Awk

Awk è un linguaggio completo per l'elaborazione di testo, con una sintassi che ricorda quella del C. Sebbene possegga un'ampia serie di funzionalità e di operatori, qui ne verranno analizzati solo un paio - quelli più utili allo scripting di shell.

Awk suddivide ogni riga dell'input che gli è stato passato in campi. Normalmente, un campo è una stringa di caratteri consecutivi separati da spazi, anche se esistono opzioni per modificare il delimitatore. Awk, quindi, analizza e agisce su ciascun singolo campo. Questo lo rende ideale per trattare file di testo strutturati -- in particolare le tabelle -- e dati organizzati in spezzoni logici, come righe e colonne.

Negli script di shell, i segmenti di codice awk vengono racchiusi da apici singoli (quoting forte) e da parentesi graffe.

echo uno due | awk '{print $1}'
# uno

echo uno due | awk '{print $2}'
# due


awk '{print $3}' $nomefile
# Visualizza allo stdout il campo nr.3 del file $nomefile.

awk '{print $1 $5 $6}' $nomefile
# Visualizza i campi nr.1, 5 e 6 del file $nomefile.

Si è appena visto il comando print di awk in azione. L'altra sola funzionalità di awk di cui è necessaria la spiegazione sono le variabili. Awk le tratta in modo simile a come sono gestite negli script di shell, anche se con una maggiore flessibilità.

{ totale += ${numero_colonna} }
In questo modo si aggiunge il valore di numero_colonna al totale di totale. Infine, per visualizzare "totale", vi è il comando di blocco di codice END, da eseguire dopo che lo script ha elaborato completamente il proprio input.
END { print totale }

Corrispondente ad END, vi è BEGIN, per il blocco di codice che deve essere eseguito prima che awk inizi l'elaborazione del suo input.

L'esempio seguente illustra come awk permetta di incrementare il numero di strumenti di verifica di testo a disposizione dello scripting di shell.

Esempio C-1. Conteggio delle occorrenze di lettere

#! /bin/sh
# letter-count.sh: Conta le occorrenze di lettere in un file di testo.
#
# Script di nyal (nyal@voila.fr).
# Usato con il permesso dell'autore.
# Ricommentato dall'autore di questo libro.
# Versione 1.1: Modificata per funzionare con gawk 3.1.3.
#               (Funziona anche con le versioni precedenti.)


INIT_TAB_AWK=""
# Parametro per inizializzare lo script awk.
conteggio=0
FILE_INDICATO=$1

E_ERR_PARAM=65

utilizzo ()
{
    echo "Utilizzo: letter-count2.sh file lettere" 2>&1
    # Per esempio:   ./letter-count2.sh nomefile.txt a b c
    exit $E_ERR_PARAM # Parametri passati allo script insufficienti.
}

if [ ! -f "$1" ] ; then
    echo "$1: File inesistente." 2>&1
    utilizzo               # Visualizza il messaggio di utilizzo ed esce.
fi 

if [ -z "$2" ] ; then
    echo "$2: Non è stata specificata nessuna lettera." 2>&1
    utilizzo
fi 

shift                      # Le lettere sono state specificate.
for lettera in `echo $@`   # Per ognuna . . .
  do
  INIT_TAB_AWK="$INIT_TAB_AWK tab_search[${conteggio}] = \"$lettera\";\
   final_tab[${conteggio}] = 0; "
  # Passato come parametro al successivo script awk.
  conteggio=`expr $conteggio + 1`
done

# DEBUGGING:
# echo $INIT_TAB_AWK;

cat $FILE_INDICATO |
# Il file viene collegato, per mezzo di una pipe, al seguente script awk.

# --------------------------------------------------------------------------------
# La versione precedente dello script usava:
# awk -v tab_search=0 -v final_tab=0 -v tab=0 -v nb_letter=0 -v chara=0 -v chara2=0 \

awk \
"BEGIN { $INIT_TAB_AWK } \
{ split(\$0, tab, \"\"); \
for (chara in tab) \
{ for (chara2 in tab_search) \
{ if (tab_search[chara2] == tab[chara]) { final_tab[chara2]++ } } } } \
END { for (chara in final_tab) \
{ print tab_search[chara] \" => \" final_tab[chara] } }"
# --------------------------------------------------------------------------------
#  Niente di così complicato, solo . . .
#+ cicli for, costrutti if e un paio di funzioni specializzate.

exit $?

# Confrontate questo script con letter-count.sh.

Per dimostrazioni più semplici dell'uso di awk negli script di shell, vedi:

  1. Esempio 14-12

  2. Esempio 19-8

  3. Esempio 15-29

  4. Esempio 33-5

  5. Esempio 9-24

  6. Esempio 14-19

  7. Esempio 27-2

  8. Esempio 27-3

  9. Esempio 10-3

  10. Esempio 15-55

  11. Esempio 9-29

  12. Esempio 15-4

  13. Esempio 9-14

  14. Esempio 33-16

  15. Esempio 10-8

  16. Esempio 33-4

  17. Esempio 15-48

Questo è tutto, per quanto riguarda awk, ma vi sono moltissime altre cose da imparare. Si vedano i relativi riferimenti in Bibliografia.