Vai alla Home Page About me Courseware Federica Living Library Federica Federica Podstudio Virtual Campus 3D Le Miniguide all'orientamento Gli eBook di Federica La Corte in Rete
 
I corsi di Scienze Matematiche Fisiche e Naturali
 
Il Corso Le lezioni del Corso La Cattedra
 
Materiali di approfondimento Risorse Web Il Podcast di questa lezione

Clemente Galdi » 8.Awk Scripting


Variabili

Come tutti i linguaggi di programmazione, awk, consente di utilizzare variabili all’interno del codice.
I nomi di variabili possono essere composti da lettere, digit e/o dal simbolo “_”, con l’unico vincolo che non possono iniziare per un digit.
Attenzione: l’utility awk interpreta le variabili in modo case-sensitive, I,e., le variabili “Var”, “var”, “VAR”, etc… sono diverse!
Alcune caratteristiche del linguaggio awk:

  • Non è necessario definire le variabili.
  • È possibile assegnare ad una variabile sia valori numerici che stringhe
  • Il tipo di dato assegnato ad una variabile può variare durante l’esecuzione del programma.
    • Attenzione agli errori logici! L’assegnazione di un valore numerico ad una variabile contenente una stringa (o vicecersa) NON genera nessun errore!
  • L’interprete awk utilizza alcune variabili built-in, e.g., NR, FS, etc. Lo script ha accesso a queste variabili e può modificarne il valore. Nell’utilizzo delle variabili built-in deve tener conto del fatto che l’interprete stesso può aggiornarle, indipendentemente dallo script.
  • Il valore di una variabile può essere modificato attraverso le operazioni di assegnazione, incremento e/o decremento.

Variabili: Conversioni

È possibile assegnare un valore ad una variabile utilizzando la seguente sintassi: nomevariabile=stringa
Ad es. X=7; y=7.8; z=1.2e3; (notazione base-esponente, I.e,. z=1200) argomento=”variabili”;
In alternativa, è possibile assegnare il valore della variabile da riga di comando utilizzando l’opzione -v dell’interprete.
Attenzione: A DIFFERENZA della shell, per utilizzare il valore di una variabile è sufficiente utilizzare il nome della variabile, E.g. x=y+z;
L’interprete awk converte automaticamente le stringhe in numeri e viceversa nel momento in cui il contesto del programma lo richiede. Ad esempio:

  • print “il valore della variabile x e’:” x
  • In questo caso, se la variabile x contiene una string, l’interprete concatena la stringa costante “il valore..” con il valore della variabile x e visualizza il risultato
  • Se la variabile x contiene un valore numerico, l’interprete, prima di eseguire la concatenazione, converte automaticamente il numero in stringa.

Si consideri il seguente esempio:  Due=2; Tre=3; print (Due Tre)+4;

In questo caso: L’assenza di un operatore nell’espressione (Due Tre) indica all’interprete di eseguire una concatenazione (tra stringhe). Le variabili (numeriche) Due e Tre vengono convertite in stringhe, e viene effettuata la loro concatenazione ottenendo la stringa “23″.
La presenza dell’operatore (matematico) “+”, indica all’interprete di convertire la stringa “23″ in intero. Viene quindi effettuata la somma degli interi 23 e 4, il cui risultato viene visualizzato.

Operazioni aritmetiche e concatenazione

Le variabili numeriche, in awk, rappresentano sempre numeri con virgola. È errore comune, per chi scrive script shell ed awk, assumere che il risultato di una operazione sia sempre un intero.
È possibile utilizzare le seguenti operazioni su variabili numeriche:

  • - Negazione, es., x=-y; z=-25;
  • + Operatore unario di conversione in valore numerico. Es. x=”32″; y=+x
  • ^ oppure ** Elevamento a potenza. Es. x=2, y=3, z=x^y;
  • * Moltiplicazione Es. x=2; y=3; z=x*y;
  • / Divisione Es. x=3; y=2; z=x/y; Attenzione il valore di z in questo caso è 1.5 NON 1. Per eseguire l’arrotondamento e’ necessario richiederlo esplicitamente utilizzando la funzione int(), e.g., z=int(x/y);
  • % Modulo. Attenzione: x % y è negativo se x<0!
  • + somma. Ad es. x=2; y=3; z=x+y;
  • - sottrazione. Ad es. x=2; y=3; z=x-y;
  • ++var e var++ operatori di pre- e post-incremento
  • –var e var– operatori di pre- e post-decremeto

Concatenazione tra stringhe, true e false

Per le stringhe esiste solo l’operatore di concatenazione che consiste nella giustapposizione di stringhe.
In alcuni casi è necessario utilizzare le parentesi per forzare l’esecuzione della concatenazione prima di altri operatori. Riprendiamo un esempio dalla lezione 6:
print “Il record “NR…”> (“outfile_” NR);
L’omissione delle parentesi sarebbe stata interpretata come ‘print… > ‘”outfile_” NR’, generando un errore di sintassi visto che l’interprete si aspetta UN solo elemento a destra del simbolo >.

In awk non esistono, come in molti linguaggi di programmazione, costanti true e false.
L’utility awk interpreta:

  • un qualsiasi valore numerico diverso da zero o una stringa non vuota come “true”
  • un qualsiasi valore numerico pari a zero o una stringa vuota assume il significato di “false”

Tipi di variabili

L’interprete associa ad ogni costante ed ad ogni variabile un attributo numerico o stringa attraverso le seguenti regole:

  • Una costante numerica o il risultato di una operazione aritmetica ha un attributo numerico.
  • Una stringa costante o il risultato di una operazione tra stringhe ha un attributo stringa.
  • Gli attributi si propagano attraverso gli assegnamenti ma non cambiano se il valore di una variabile viene utilizzato in un espressione.

Awk considera gli input dell’utente (e.g., i campi del record letto dal file) come valori numerici mentre le costanti definite nel codice, se anche composte da soli digit, vengono considerate stringhe.
Il confronto tra variabili e costanti avviene utilizzando gli operatori appositi a seconda degli attributi numerico/stringa degli item da confrontare.
In generale, l’interprete tende ad eseguire confronti tra stringhe. Solo nel caso in cui gli elementi da confrontare siano entrambi numerici (o “stringhe numeriche”) vengono utilizzati operatori numerici.

Operatori di confronto ed espressioni booleane

Il confronto tra item, siano essi variabili o costanti, numerici o stringhe, vengono effettuati dai medesimi operatori di confronto, indicati di seguito:

  • X<Y: Vero se X è minore di Y
  • X <= Y: Vero se X è minore o uguale ad Y
  • X > Y: Vero se X è maggiore di Y
  • X >= Y : Vero se X è maggiore o uguale ad Y
  • X == Y : Vero se X è uguale ad Y
  • X != Y : Vero se X è diverso da Y
  • X ~ Y: Vero se la stringa X corrisponde all’espressione regolare definita da Y
  • X !~ Y: Vero se la stringa X NON corrisponde all’espressione regolare definita da Y

Una espressione booleana è una combinazione di operazioni di confronto o di matching attraverso i seguenti operatori booleani:

  • exp1 && exp2: (AND) Vera se entrambe le espressioni sono vere.
  • exp1 || exp2: (OR) Vera se almeno una tra exp1 ed exp2 è vera.
  • !exp: (NOT) Vera se exp è falsa

Statement di controllo

Gli statement di controllo consentono l’esecuzione condizionata di parti del codice. Awk fornisce i seguenti statement: [Mostra codice

if-then-else

Un esempio di utilizzo dello statement if-then-else: Mostra codice.
Un secondo esempio di script: Mostra codice.

Il costrutto if-then-else ha la seguente sintassi:
if (condizione) codice-then [ else codice-else ]
Se la condizione è vera, viene eseguito il codice-then, altrimenti, se presente, viene eseguito il codice-else. Lo statement else è opzionale.
La condizione può essere una qualsiasi espressione. Si rammenta che in awk, uno 0 od una stringa vuota equivale a "falso", mentre un valore numerico non nullo od una stringa non vuota equivale è "vero".
È possibile comporre espressioni elementari utilizzando gli operatori and (&&), or (||) e not (!).

while

Il costrutto while ha la seguente sintassi:
while (condizione) body
L’interprete verifica la condizione e, se questa è vera, esegue il body. Se la condizione è inizialmente falsa, il body non viene mai eseguito.
Se il body consiste di un’unica istruzione, può essere posto sulla stessa riga del while e non è necessario utilizzare il separatore “;”.
Se il body consiste di più comandi, è necessario utilizzare le parentesi graffe per definirne l’inizio e la fine.
Per la condizione valgono le stesse considerazioni fatte per il costrutto if-then-else.
In questo esempio: Mostra codice, nel blocco BEGIN vengono inizializzate le variabili somma, pari ed ind. Quest'ultima inizializzazione è inutile, se il file contiene più righe, visto che questo blocco viene eseguito una sola volta.
Il primo while visualizza gli elementi contenuti nella riga in esame. Utilizzando come input il seguente file:  Mostra codice, viene scartata la prima riga visto che, su questa riga, quando ind=1, $ind=1.
A questo punto è necessario reinizializzare la variabile ind affinché il secondo while possa essere eseguito.

Si noti che l'operatore di post-incremento consente di verificare il valore di ind "prima" del suo incremento. In realtà, l'operatore incrementa la variabile ind ma ritorna il valore della variabile precedente l'operazione.

do-while

Il costrutto do-while ha la seguente sintassi:
do body while(condizione)
L’unica differenza tra I costrutti while e do-while è che quest’ultimo esegue il body prima di verificare la condizione.
È chiaro, quindi, che il body viene eseguito almeno una volta indipendentemente dal fatto che la condizione sia vera o falsa.
L’esempio:  Mostra codice, riporta una variante dello script appena visto, riscritto con in costrutto do-while.
È da notare la diversa inizializzazione della variabile ind. A differenza dell'esempio precedente, il valore di ind viene incremento alla fine del costrutto. In questo caso è quindi necessario che ind punti direttamente il primo campo del record in esame.
Sebbene il do-while renda più immediato l'utilizzo dell'operatore di pre-incremento a fine ciclo ("esegui la prossima iterazione se il prossimo valore dell'indice è valido"), è necessario prestare massima attenzione alle condizioni di uscita. Si ricorda che i campi del record in esame vengono numerati da 1 a NF. Quando il valore di ind è pari a NF-1, il suo pre-incremento, accoppiato ad una condizione "
Infine si fa presente che la condizione di uscita da un ciclo do-while, come nel caso del costrutto while, può essere una qualunque espressione booleana.

for

Elemento distintivo dei costrutti while e do-while è la possibilità di definire condizioni di uscita arbitrarie da un loop.
Esistono molti casi in cui il numero di volte in cui deve essere eseguito il body è noto prima dell’esecuzione del ciclo, e.g., il numero di elementi n un array.
In questi casi, l’utilizzo del costrutto for è conveniente in quanto consente la definizione compatta delle fasi di inizializzazione, verifica della condizione di uscita e modifica dell’indice.
La sintassi del costrutto for è la seguente:
for (inizializzazione; condizione; incremento)
body
L’interprete awk, esegue una volta l’inizializzazione e, finché la condizione è vera, esegue il body e, successivamente, l’incremento.
Nel costrutto for:

  • NON è possibile inizializzare più variabili nello statement di inizializzazione, tranne utilizzando la sintassi I=k=…=valore
  • NON è possibile modificare più variabili nello statement di incremento.
  • L’espressione di “incremento” può modificare l’indice in modo arbitrario, I.e., non è richiesto che sia “incrementato di una unità”
  • la condizione di uscita può essere una qualsiasi espressione booleana dipendente (direttamente od indirettamente) dall’indice.

Un esempio di utilizzo del ciclo for: Mostra codice

switch

Lo statement switch consente di evitare l’annidamento di costrutti if-then-else. La sintassi del costrutto è la seguente: Mostra codice. Attenzione: questo costrutto potrebbe NON esistere o NON essere abilitato in alcuni interpreti.
A differenza della maggior parte dei linguaggi di programmazione, ogni istruzione case può contenere una costante (numerica o stringa) o una espressione regolare.
Quando l'espressione corrisponde ad uno dei valori specificati, l'azione associata viene eseguita. A quel punto l'interprete riprende l'analisi del valore contenuto al case successivo. Questo processo termina quando viene eseguito uno dei seguenti statement: break, continue, next, nextfile o exit.
Il seguente esempio: Mostra codice, mostra alcune peculiarità appena descritte.
L'interprete valuta l'espressione e confronta il suo valore con:
- L'intero 9. In questo caso, viene eseguita un confronto numerico. Visto che non c'è un break, anche in caso di uguaglianza, lo statement NON viene interrotto.
- La stringa "9": Viene eseguito il confronto convertendo il valore del risultati in stringa. Qualora vi sia una corrispondenza, la presenza di break interrompe l'esecuzione dello statement switch.
- Una espressione regolare: l'interprete verifica che la stringa ottenuta dalla conversione del risultato dell'espressione contenga il pattern specificato.
- Default: eseguito se nessuno dei casi precedenti è valido. Si noti che l'assenza di break nell'azione associata a default non impedisce l'analisi dell'ultimo case.

break e continue

Lo statement break interrompe l’esecuzione di un ciclo, for, while o do-while e dello switch. Nel caso di loop annidati, viene interrotto solo il loop più interno.
L’interprete esegue la prima istruzione successiva alla fine del loop interrotto.
A differenza della shell, break NON prende parametri. Quindi non è possibile interrompere contemporaneamente più loop annidati.

Lo statement continue interrompe l’esecuzione di un ciclo, while o do-while. L’effetto di continue è quello di forzare l’interprete a “saltare” le istruzioni del body e di riprendere lo stesso loop dal ciclo successivo.

Come nel caso degli script shell, è necessario prestare la massima attenzione nell’utilizzo del continue nei cicli while e do-while. L’esecuzione di un continue prima della modifica delle variabili che controllano la condizione di uscita può portare ad un ciclo infinito.

Il seguente script Mostra codice riporta un esempio di utilizzo di break e continue.
Il while esterno incrementa la variabile i ed esegue il for interno solo se il valore di i è pari. Difatti lo statement continue viene eseguito quando la condizione è vera, i.e., i%2=1.
Il for interno incrementa l'indice j e visualizza le coppie i,j solo se i<j. Infatti quando le due variabili assumono lo stesso valore, viene eseguito il break che interrompe il ciclo for.

Output atteso: Mostra codice.

next e nextfile

Lo statement next forza l’interprete ad interrompere l’elaborazione del record corrente ed a leggere il record successivo dal file.
Si noti che, nel caso in cui lo script awk sia composto da più regole, l’esecuzione di next NON interrompe solo l’esecuzione della “regola corrente” ma forza l’interprete a NON eseguire nessuna altra regola.
Lo standard POSIX NON definisce il comportamento dell’interprete nel caso in cui next sia eseguito nei blocchi BEGIN o END.

Lo statement nextfile forza l’interprete ad interrompere l’elaborazione del record corrente ed a leggere il primo record del file successivo al file corrente (se esiste).
Questo statement è, chiaramente, più forte rispetto allo statement next.
Il seguente script: Mostra codice, visualizza, per ogni file in input, tutte le righe di posizione pari. In questo caso, l'espressione FNR%2 ritorna uno ("vero") quando l'interprete analizza le righe dispari del file. In questo caso viene eseguito lo statement next che forza la lettura del record successivo, evitando la print $0.
Il seguente script: Mostra codice, invece, visualizza le righe pari dei soli file il cui nome corrisponde alla RE /^slide/, i.e., il cui nome inizi per 'slide'.
L'interprete scarta, invece, tutti i file che non corrispondono al criterio descritto, dopo averne letto il primo record.
L'utilizzo della variabile Fname è solo utile al fine di visualizzare una sola volta il nome del file.

exit

Lo statement exit termina l’esecuzione dello script, con le seguenti regole:
Se exit è eseguito nel blocco BEGIN, l’interprete non legge alcun record dall’input ma esegue il blocco END.
Se exit è eseguito nel blocco END, l’interprete termina lo script immediatamente.
Se exit è eseguito all’interno di una regola, l’interprete interrompe la lettura dell’input ed esegue il blocco END.
Lo statement può ricevere un parametro intero opzionale. Il valore del parametro viene ritornato come exit value dall’interprete. Se exit è invocato senza parametri, l’interprete ritorna il valore zero. Si rammenta che per la shell, il valore zero equivale a “successo”.
Nel caso in cui l’exit viene eseguito:

  • Una prima volta all’interno del blocco BEGIN od in una regola con un exit value x (causando l’esecuzione del blocco END)
  • Ed una seconda volta all’interno del blocco END senza parametri

Il valore di ritorno dell’interprete sarà x.

Un esempio di utilizzo di exit: Mostra codice

Array in awk

Come altri linguaggi di programmazione, awk fornisce la possibilità di utilizzare array. Esistono però, rispetto alla maggior parte dei linguaggi di programmazione, alcune differenze fondamentali:

  • Non è necessario definire la dimensioni di un array;
  • Un array può contenere, contemporaneamente, numeri e stringhe;
  • Qualsiasi numero (intero o non) o stringa può essere utilizzato come indice;

In awk, gli array sono “associativi”, I.e., ogni elemento di un array è in realtà la coppia (indice, valore). Questo rende possibile:

  • Aggiungere elementi all’array in qualsiasi momento, indipendentemente dal valore dell’indice;
  • Utilizzare, contemporaneamente, numeri e stringhe come indici dell’array.

Attenzione:

  • Il nome di un array deve seguire le stesse regole dei nomi di variabile, I.e., è composto da lettere, digit e/o dal simbolo “_”, con il vincolo che il primo carattere non sia un digit.
  • Sebbene sia possibile utilizzare valori numerici come indici di array, l’interprete converte il valore numerico in stringa prima del suo utilizzo. Modificare la variabile built-in CONVFMT (che indica all’interprete come convertire numeri in stringhe) all’interno di un script che utilizza array può avere effetti sull’esecuzione.
  • L’interprete analizza gli indici in modo case-sensitive! Quindi nomearray["x"] e nomearray["X"] sono elementi diversi dell’array.

Array in awk (segue)

Per referenziare l’elemento “indice” dell’array “nomearray” è possibile utilizzare la sintassi nomearray[indice]
Il riferimento ad un indice che non è presente nell’array ritorna la stringa vuota “”.
È possibile effettuare le seguenti operazioni:

  • Assegnazione: Per assegnare un valore y all’elemenco con indice x dell’array nomearray è possibile usare nomearray[x]=y
  • Scorrimento: Per scorrere gli elementi nell’array nomearray, è possibile utilizzare la seguenti sintassi:
    • for (var in nomearray)
    • body
  • Verifica: È possibile verificare se è presente una coppia (indice, valore) in un array utilizzando l’espressione (indice in nomearray), che ritorna vero nel caso la coppia esiste.
  • Cancellazione: Per cancellare un elemento con indice x dall’array nomearray è necessario utilizzare lo statement delete nomearray[x]. In alternativa è possibile cancellare tutti gli elementi dell’array omettendo l’indice dell’elemento da cancellare, I.e., delete nomearray.

Attenzione: la cancellazione di un elemento con indice x da un array NON corrisponde ad assegnare il valore “” all’indice x.

Array in awk: esempi

Il seguente script: Mostra codice, riporta esempi di assegnazione ad un array.
Sono da notare:
L'ordine in cui vengono visualizzati gli elementi dell'array è dipendente dall'implementazione dell'interprete e NON è predicibile.
Il valore assegnato da a[1]="numero 1" viene sostituito da a["1"]="stringa 1" perché l'interprete converte il numero 1 nella stringa "1". Quindi la seconda assegnazione NON inserisce un nuovo elemento nell'array ma modifica un elemento esistente.
È possibile utilizzare valori numerici non interi come indici dell'array, come nel caso a[3.5]=3.5. Attenzione a non confondere I ruoli. In a[3.5], il numero "3.5" è l'indice dell'array, mentre l'elemento a destra dell'operatore di assegnazione è il valore assegnato.
Effetto della variabile CONVFMT: L'interprete trasforma ogni valore numerico non intero utilizzando il formato specificato in questa variabile. Lo script indica di mantenere solo I primi due digit dopo la virgola. Per questa ragione, sebbene I numeri 1.123 ed 1.12 siano diversi, all'atto della conversione saranno entrambi convertiti nelle stringhe "1.12". Quindi la seconda assegnazione porta ad una sovrascrittura del valore "Errore" assegnato all'indice 1.123.
La variabile CONVFMT ha effetto solo sulla parte decimale dei valori numerici. La conversione di interi avviene sempre nel modo "ovvio".

Un possibile output: Mostra codice

Array in awk: esempi (segue)

Un esempio di utilizzo di array e relativo output: Mostra codice
Lo script dell'esempio riporta un altro problema che può verificarsi a causa della modifica di CONVFMT.
Lo script assegna il valore 7 all'indice 3.15.
Successivamente viene modificato il criterio di conversione, riducendo ad uno il numero di digit utilizzati per la conversione.

Il test successivo di appartenenza fallisce, sebbene l'indice richiesto sia lo stesso utilizzato per l'inserimento.

Array in awk: esempi (segue)

Un esempio di cancellazione di elementi di array: Mostra codice.
L'array viene inizializzato con le coppie (I,I), con I=1...5.
Successivamente vengono cancellati gli elementi di posto dispari utilizzando lo statement delete.
Quindi vengono visualizzati gli elementi contenuti nell'array utilizzando due possibili opzioni:
Viene prima impiegato lo statement "in" per elencare tutti gli indici presenti nell'array
Viene eseguita una scansione su tutti I possibili indici tra 1 e 5 ed, utilizzando lo statement "in" nel costrutto if viene verificata la presenza di un elemento nell'array.

Successivamente viene eseguita una "cancellazione" (SBAGLIATA), assegnando il valore "" a tutti gli indici presenti nell'array.
L'errore si evince dal fatto che, a differenza della delete, rieseguendo la scansione dell'array, gli elementi che avevamo "cancellato", in realta', sono ancora presenti nell'array ma con un valore associato pari a "".

Infine la delete è utilizzata per cancellare tutti gli elementi dell'array.
Output: Mostra codice

Awk e funzioni built-in

All’interno di uno script awk è possibile invocare funzioni definite dal linguaggio per la manipolazione di variabili numeriche e stringhe.
Per invocare una funzione, è sufficiente scrivere il nome della funzione, indicando gli eventuali parametri tra parentesi tonde. Nel caso in cui la funzione non prende parametri, è comunque necessario riportare le parentesi tonde. Ad es., y=int(x); z=rand().
Sebbene eventuali spazi tra il nome della funzione built-in e le parentesi vengono scartati dall’interprete, è buona norma NON interporre spazi. Come vedremo, la presenza di questi spazi generano errori per le funzioni definite dall’utente.
Se uno dei parametri passati alla funzione è una espressione, si tenga conto che l’espressione viene sempre valutata completamente prima di invocare la funzione. Ad es., nell’invocazione di log(I++), nonostante l’operatore utilizzato sia di post-incremento, l’interprete valuta I++, incrementando il valore di I e, successivamente invoca log().

Qualora la funzione riceva in input più parametri, ed esistono più espressioni passate alla funzione, l’ordine di valutazione delle singole espressioni NON è definito. Ad es., per l’invocazione atan2(I++, 2*I), NON è possibile, a priori, sapere se il post-incremento viene eseguito prima o dopo il prodotto.
Nelle slide successive vengono riportati alcuni esempi di funzioni disponibili.

Alcuni esempi di funzioni compatibili

Le funzioni numeriche built-in:

int(x): intero compreo tra zero ed x,
troncato verso lo zero,
e.g. int(3.9)=3, int(-3.9)=-3
sqrt(x): radice quadrata di x
exp(x): ritorna e^x
log(x): logaritmo di x in base e
sin(x): seno di x
cos(x): coseno di x
atan2(y,x). Arcotangente di y/x in radianti.
rand(): ritorna un valore casuale
nell’intervallo [0,1)
srand(x): assegna il seed del generatore
pseudo-casuale per la generazione di valori
casuale ad x.

Se il parametro è omesso, viene utilizzato il valore corrente di data ed ora.

Alcuni esempi di funzioni compatibili (segue)

Esempi di funzioni built-in su stringhe:

index(sub, stringa): ritorna l’indice della prima occorrenza di sub in stringa.
Ritorna zero se sub non è presente in stringa.
length(x). Se x è una stringa, ritorna il numero di Caratterin in x.
Se x è un numero, viene convertito In stringa y e la funzione ritorna la lunghezza di y.
Se x è una espressione numerica, l’espressione viene valutata e la funzione ritorna la lunghezza della stringa che rappresenta il risultato.
substr(stringa, inizio, [lung]): estrae una sottostringa dal string, partendo dal carattere con indice inizio. Il parametro lung è opzionale. Se presente, la funzione estrae lung caratteri da stringa,  a partire da inizio.

Awk e funzioni definite dall’utente

Il linguaggio consente di definire funzioni all’intero degli script. La sintassi per la definizione di una funzione è la seguente: Mostra codice.
È possibile definire una funzione tra qualsiasi coppia di regole (NON all'interno di una regola!). Non è necessario definire la funzione prima del suo utilizzo. Difatti l'interprete awk legge l'intero script prima di iniziare l'esecuzione.
La lista dei parametri è opzionale. Come in tutti i linguaggi di programmazione, i nomi dei parametri vengono utilizzati per mantenere una copia locale (alla funzione) del valore passato dalla funzione chiamante.
Una funzione può invocare funzioni ed, in particolare, può invocare se stessa. Awk, consente quindi la definizione di funzioni ricorsive.
Come per le funzioni built-in, l'invocazione di una funzione definita dall'utente avviene utilizzando il nome seguito dalla lista dei parametri inclusa tra parentesi tonde. NON è possibile lasciare spazi (o tab) tra il nome della funzione e l'elenco dei parametri.
Il passaggio dei parametri è fatto per valore, i.e., l'interprete esegue una copia del valore della variabile nella funzione chiamante e la funzione opera su questa copia.
Quando il parametro è un array, il passaggio dei parametri diventa per riferimento, i.e.,. Ogni modifica all'array nella funzione è visibile nella funzione chiamante.
Le funzioni possono ritornare una espressione utilizzando lo statement return espressione. Se espressione è omesso, il valore di ritorno è impredicibile. Quando l'interprete raggiunge la fine di una funzione senza trovare un return, aggiunge automaticamente un return senza espressione.
Esempio di script e relativo output: Mostra codice

Funzioni definite dall’utente e scoping

Particolare attenzione deve essere posta allo scoping delle variabili.
Le uniche variabili locali alla funzione sono solo quelle indicate nell’elenco del parametri. Le altre variabili sono sempre “globali”. D’altro canto è possibile invocare una funzione passando un numero di parametri inferiore a quelli attesi dalla funzione. In questo caso, I parametri non utilizzati assumono il valore di variabili locali alla funzione con valore iniziale pari a “”.
Nell’esempio: Mostra codice, la funzione a riceve due parametri, b e d ed utilizza una variabile c. Semplicemente visualizza I valori di b, c e d, assegna loro il valore 1 e visualizza di nuovo il loro valore.
Il blocco BEGIN utilizza le stesse variabili assegnando loro il valore 7. La funzione a viene invocata passando come unico parametro la variabile b.
All'interno della funzione le variabili:

  • b: è un parametro, è locale ed assume il valore 7 passato all'atto dell'invocazione. Ogni modifica a b NON è visibile all'esterno.
  • d: è una variabile locale, (visto che l'invocazione è stata fatta passando un solo parametro) ed assume il valore "". Ogni modifica alla variabile d NON è visibile all'esterno.
  • c: è una variabile "globale" ed assume lo stesso valore che assume nel blocco BEGIN. Ogni modifica a C è visibile nello script.

Output dello script: Mostra codice.

I materiali di supporto della lezione

Bash guide for beginners: Capitolo 6

GAWK: Effective Awk Programming: Cap. 6 (par. 4); Cap. 7 (par. 1-7); Cap. 8

  • Contenuti protetti da Creative Commons
  • Feed RSS
  • Condividi su FriendFeed
  • Condividi su Facebook
  • Segnala su Twitter
  • Condividi su LinkedIn
Progetto "Campus Virtuale" dell'Università degli Studi di Napoli Federico II, realizzato con il cofinanziamento dell'Unione europea. Asse V - Società dell'informazione - Obiettivo Operativo 5.1 e-Government ed e-Inclusion