domenica 25 novembre 2012

Un po' di AWK. Dodicesima parte.

Salve!

E il sequel "Un po' di AWK" continua. Un po' a rilento, ma continua. Oggi parliamo del ciclo for e delle istruzioni break e continue. Ma anche di while. Insomma, parliamo di tante cose. Mi rendo conto che forse 'sti post su awk non sono il massimo della linearità, ma mi sforzo di fare del mio meglio. Partiamo sempre dalla nostra tabella(tabella.txt).

2012   gen  feb  mar  apr  mag  giu  lug  ago
Marco 1200 1400 1000 1500 1800 1400 1000 1200
Luca  1800 2300 2000 1000 1000 1150 1230 1200
Carlo 2000 1200 1000 1000 1200 1100 2000 1300
Nino  1000 1250 1900 1100 1350 1100 1290 1400
Luigi 1500 1000 1250 1100 1200 1120 1000 1190
Ennio 2000 1000 1550 1300 1000 1100 0    1350
Nella prima colonna abbiamo un elenco di operai e, a fianco di ciascuno di essi, i relativi stipendi percepiti nei primi 8 mesi del 2012.

Bene. A noi interessa sapere la somma degli stipendi di ciascuno operaio. Ad esempio, vogliamo sapere quanto ha guadagnato Marco nei primi otto mesi dell'anno.

La tabella, così come è stata strutturata, pone dei problemi evidenti. Si può immaginare awk come un evidenziatore (di colore giallo). Inizia a colorare la tabella dalla prima riga, da sinistra verso destra. E dato che noi dobbiamo sommare i campi di ciascun record, awk si troverebbe in situazioni come queste:

2012+gen+feb+mar+apr+mag....
oppure
Marco+1200+1400+1000....

Ecco allora l'esigenza di trovare un modo di dire ad awk di non tenere conto della prima colonna e della prima riga. In pratica di non tenere conto di ciò che ho scritto in rosso.

Per non far leggere ad awk la prima riga faccio ricorso al costrutto if.

if (NR > 1 ) {......}

Che poi è come dire ad awk di iniziare ad evidenziare la tabella partendo dalla seconda riga: per il numero di record (NR) maggiore di 1.

E per non far leggere la prima colonna? Ho detto che oggi si parla di cicli, perciò il problema va risolto in relazione ad essi. La soluzione è ancora più semplice della prima. Basta inizializzare la variabile i al valore 2. Oppure inizializzarla al valore 1 e poi usare l'istruzione continue. Vedremo entrambi i casi.

Iniziamo con il primo script (es0.awk)
#!/usr/bin/awk -f

BEGIN {
       print " \f##########RETRIBUZIONE###########\n"       
}
{ 
  if (NR > 1) {
         i=1; totale=0
         while (i <= NF) {
                totale = totale+$i;
                i++
                if (i==1){
                    continue
                } 
         } 
         print NR, "il Signor",$1, "in otto mesi ha guadagnato", totale, "euro" 
   }         
}
END {
     print "\n"
}

Riguardo al primo problema, di non far leggere ad awk la prima riga, abbiamo ovviato con if (NR >1); Circa il secondo problema, cioè di non leggere la prima colonna, abbiamo inizializzato la variabile i al valore 1 e poi abbiamo usato l'istruzione continue: if (i==1) {continue}. Che sta a significare più o meno questo: Se i è uguale ad uno, salta il campo. In altri termini, quando i è uguale a $1, non tenerne conto. Ricordate che $1 è il primo campo?

Passiamo al secondo script (es1.awk).
#!/usr/bin/awk -f

BEGIN {
       print " \f##########RETRIBUZIONE###########\n"
}
{
 if (NR > 1 ) {
     totale = 0
     for (i=2; i<=NF; i++) {
          totale = totale+$i;
             if ( i == 5 ) {
                  break
             } 
     }
     print NR, "il Signor",$1, "nei primi quattro mesi ha guadagnato", totale, "euro"
 }
}
END {
     print "\n"
}

Questa è il modo più ovvio per risolvere il secondo dei nostri problemi. In tal caso abbiamo inizializzato la variabile i al valore due, che significa che il primo campo non viene proprio preso in considerazione... In questo script abbiamo usato anche l'istruzione break, ma per altri scopi. In pratica, quando la variabile i è uguale a 5, break non permetterà al ciclo di andare avanti...Non è che si esce dal ciclo...più semplicemente il ciclo arriva a 5 e ricomincia...

Descriviamo brevemente il ciclo for. Esso è un ciclo c.d. enumerativo e consta di tre elementi: da una variabile-contatore, che abbiamo inizializzata a 2 (i=2), da una condizione (i<=NF)  e da una istruzione che incrementa il valore della variabile-contatore di una unità (i++). In estrema sintesi, finché il valore della variabile-contatore i rispetta la condizione “i<=NF” il blocco delle azioni (quello racchiuso tra parentesi graffe) va ripetuto. Ogni volta che il blocco delle azioni viene ripetuto, l'istruzione i++ incrementa di una unità la variabile i. Incrementa oggi, incrementa domani...il valore della variabile i diventa maggiore del numero dei campi (NF)...e così il ciclo smette di  eseguire il blocco (che nel nostro caso è costituito da totale = totale + $i  e dal costrutto if con l'istruzione break di cui abbiamo già parlato).

Come potete vedere dall'immagine, l'istruzione break ha permesso ad awk di non tenere conto dei mesi di maggio, giugno, luglio e agosto, cioè degli ultimi quattro campi.

Per oggi basta così. La prossima volta parleremo di arrays...e ci sarà veramente da divertirsi... Intanto vi ricordo che l'indice del sequel "Un po' di AWK" lo trovate qui

Alla prossima!


Nessun commento:

Posta un commento