[precedente] Creare CD - Copertina - Giochi [successivo]

Articoli


OPEN

AWK questo sconosciuto

Vi sarà sicuramente capitato di dover estrarre dei dati da files di testo o di effettuare delle modifiche riga per riga, eventualmente condizionate dalla presenza di certi pattern, spesso considerando i dati di input come composti da parole o campi. Se avete frequentemente esigenze di questo tipo AWK è lo strumento che fa per voi. Naturalmente potreste scrivere dei meravigliosi programmi in C per fare ciò che vi serve ma dovreste perdere delle intere giornate per scrivere del codice ad-hoc che poi probabilmente non usereste più, e di solito ci mettereste di meno a fare il lavoro a mano.

Volendo dare una definizione sintetica di AWK lo si può definire come un filtro generico per files di testo basato su pattern-matching e programmabile con un linguaggio molto simile al C ma di utilizzo molto più semplificato. Il nome AWK deriva dalle iniziali dei suoi tre inventori originali, Aho, Weinberger e Kernighan, tutti personaggi abbastanza famosi nel campo della computer-science.

Di AWK ne esistono diverse versioni e implementazioni. Io farò riferimento alla implementazione GNU, detta gawk, che oltre a rispettare lo standard POSIX relativo ad AWK ha come sempre qualche funzionalità in più rispetto alle altre implementazioni commerciali che potete trovare in giro. Il Free Software è sempre il meglio!

L'idea che sta alla base di AWK è quello di elaborare una riga alla volta dei files di input, eseguendo azioni diverse a seconda che la riga stessa soddisfi certe condizioni o contenga certi patterns. I programmi scritti in AWK sono strutturati un po' diversamente rispetto a quelli in linguaggi tradizionali. Non esistono infatti un'inizio e una fine del programma stesso, e non è necessario dichiarare le variabili e gestire tutta la solita trafila dell'I/O e del parsing dei dati. A tutto questo ci pensa automaticamente AWK. Quello che resta da fare al programmatore è solamente specificare come devono essere elaborati i dati di input a seconda dei vari patterns in essi contenuti. Un programma AWK è quindi costituito solamente da una lista di regole composte da un pattern ed una corrispondente azione da eseguire se il pattern è soddisfatto:

  pattern { azione }
  pattern { azione }
  ...
AWK si incarica automaticamente di aprire e chiudere i files di input, di leggerne il contenuto una riga alla volta e di applicare a ciascuna le regole definite dal programmatore. Inoltre appena letta una riga AWK la separa automaticamente in campi, in base ad un delimitatore definibile, li assegna a delle variabili predefinite ed aggiorna automaticamente altre variabili di utilità generale, come il numero di righe lette e il numero di campi della riga corrente. Si tratta di operazioni più o meno standard che di solito si devono codificare a mano (reinventando ogni volta l'acqua calda) e che invece AWK esegue automaticamente, tutta fatica risparmiata per il programmatore. Per ciascuna riga di input vengono poi esaminate tutte le regole specificate e vengono eseguite le azioni corrispondenti a tutte quelle i cui pattern risultano soddisfatti. In pratica può succedere che per una certa riga di input non sia soddisfatto nessun pattern e quindi non venga eseguita nessuna azione, oppure che ne sia soddisfatto più di uno, nel qual caso vengono eseguite tutte le azioni corrispondenti, nell'ordine in cui sono state specificate le regole.

La potenza di AWK rispetto ad altri strumenti simili (grep, sed, cut, ecc.) è la possibilità di definire delle azioni completamente arbitrarie da effettuare sui dati di input utilizzando un vero linguaggio di programmazione, senza tuttavia essere costretti a dover gestire tutte le complicazioni tipiche dei linguaggi tradizionali. Il linguaggio di AWK è inoltre dotato di un ricco insieme di funzioni di base, fra cui quelle per la gestione di pattern matching ed espressioni regolari, e permette di gestire in modo molto semplice stringhe ed array associativi. È infine possibile definire delle proprie funzioni, come in qualsiasi linguaggio di programmazione che si rispetti, ed e' sempre possibile richiamare un programma esterno quando non si è in grado di fare una cosa direttamente con AWK.

Qualche esempio pratico

Supponiamo di voler estrarre da un elenco di nomi e numeri di telefono tutte le righe che contengono il nome MARIO. Possiamo fare cosí:

  cat elenco.txt | awk '/MARIO/ { print }'
oppure anche:
  awk '/MARIO/ { print }' file1 file2 file3
oppure semplicemente:
  cat elenco.txt | awk '/MARIO/'
In questi esempi ho eseguito AWK passando direttamente nelle linea di comando il programma da interpretare, costituito da una sola regola che dice di stampare la riga di input quando questa contiene la stringa 'MARIO'. Tutto ciò che non contiene MARIO viene letto ma non stampato in output. Notate che i dati da elaborare possono essere contenuti in files i cui nomi sono specificati nella linea di comando oppure semplicemente passati in standard input come per qualsiasi programma unix. In seguito userò soprattutto questa seconda tecnica per evidenziare il concetto che AWK può essere usato come filtro di dati.

Negli esempi precedenti il pattern è costituito dall'espressione regolare racchiusa fra / / mentre l'azione corrispondente è quella racchiusa fra { }. Notate che il pattern oppure l'azione possono essere omessi. Se non specifico il pattern significa che l'azione deve essere eseguita per qualsiasi riga di input, mentre se non specifico l'azione (come nell'ultimo esempio) significa che voglio semplicemente stampare la riga di input, che è stata assegnata automaticamente alla variabile $0. Negli esempi precedenti il programma AWK è stato specificato direttamente nella linea di comando. Ovviamente nel caso di programmi più lunghi di qualche riga ciò non è molto pratico, in tal caso si salva il programma in un file e si specifica ad AWK il nome del file da eseguire:

  echo '/MARIO/ {print $0}' > cerca-mario.awk
  cat elenco.txt | awk -f cerca-mario.awk
È possibile specificare più files contenenti codice AWK da eseguire, per esempio utilizzando delle librerie di funzioni standard. I vari files vengono concatenati insieme come se fossero un unico programma:
  cat /etc/passwd | awk -f ~/crack.awk -f /usr/share/awk/passwd.awk
Vediamo ora un esempio più complicato di un programma AWK che mi consente di estrarre il mittente e il soggetto da un messaggio di posta elettronica:
  #!/usr/bin/awk -f
  # Estrae il From e il Subject da una mail.
  ($1 == "From:")    { print(substr($0,7)) }  # mittente
  ($1 == "Subject:") { print(substr($0,10)) } # soggetto
Qui ho usato il meccanismo standard del #! che mi consente di richiamare lo script direttamente col suo nome una volta che l'ho reso eseguibile. Da questo esempio possiamo pure intuire che il carattere # serve ad iniziare un commento, anche a metà di una riga. Possiamo inoltre vedere come le variabili $1 ... $N vengono automaticamente inizializzate con i campi in cui è stata suddivisa la riga di input. Per esaminare il quinto campo userò pertanto la variabile $5, mentre la variabile $0 contiene l'intera riga di input.

Altre variabili che vengono settate automaticamente da AWK dopo la lettura di ogni riga sono NF, che contiene il numero di campi del record corrente, NR, che contiene il numero totale di record letti, FILENAME, che contiene il nome del file di input corrente, e molte altre ancora.

Una cosa interessante è che se si modifica il valore di un campo viene modificato anche l'intero record di input contenuto in $0, come si vede dal seguente esempio. La stessa cosa succede se si modifica la variabile NF.

  #!/usr/bin/awk -f
  # Come l'esempio precedente ma in italiano
  ($1 == "From:")    { $1 = "Mittente:"; print }
  ($1 == "Subject:") { $1 = "Argomento:"; print }
La suddivisione del record in campi avviene automaticamente utilizzando il valore della variabile FS, che per default (tipica esclamazione usata dai programmatori) è una sequenza qualsiasi di spazi e tab. Se voglio estrarre da /etc/passwd tutti gli utenti con la password bloccata posso utilizzare il seguente comando:
  cat /etc/passwd | awk 'BEGIN { FS=":" } ($2 == "*") { print $3,$1 }'
In questo esempio ho usato un pattern particolare, BEGIN, che per definizione viene soddisfatto solo prima di leggere la prima di riga di input. In altre parole il pattern BEGIN serve a specificare un'eventuale inizializzazione del programma che deve essere eseguita prima di cominciare a elaborare i dati. In questo esempio ho settato la variabile FS con la stringa ":" in modo che le righe di /etc/passwd vengono suddivise correttamente nei campi corrispondenti. Esiste anche un pattern END che viene eseguito quando AWK ha terminato di elaborare tutti i dati di input, in modo da poter eseguire delle azioni di chiusura, per esempio stampare dei totali calcolati in precedenza.

Oltre alla variabile FS, che descrive il separatore dei campi di input, e' possibile settare la variabile OFS che specifica il separatore con cui vengono stampati i campi in output. Posso pertanto riscrivere il file delle password con le virgole al posto dei due punti semplicemente con:

  cat /etc/passwd | awk 'BEGIN { FS=":"; OFS="," } { print }'

Gli esempi che ho illustrato finora vi fanno anche vedere che con pochissime righe di codice è possibile scrivere dei programmi AWK che fanno qualcosa di utile. Provate ora a pensare a quanto codice in C dovreste scrivere per realizzare delle cose simili e capirete perché vi conviene conoscere almeno un po' AWK.

Il linguaggio di programmazione di AWK

Come ho già anticipato l'azione associata a ciascun pattern può essere specificata utilizzando un linguaggio di programmazione simile al C. Se già sapete programmare in C non avrete difficoltà ad usare AWK. Ci sono però alcune differenze sostanziali rispetto al C da tenere presenti. La prima è che in AWK esiste un unico tipo di dato, la stringa ASCII, che viene utilizzato come stringa o come numero a seconda del contesto. La seconda è che non devo dichiarare le variabili del mio programma e che queste assumono dei valori di default (la stringa vuota "" o il numero 0) se vengono referenziate senza essere state inizializzate (vedi l'esempio del totalizzatore che usa la variabile sum senza inizializzarla). Non esistono le strutture o gli array e soprattutto mancano i puntatori e tutte le complicazioni che questi si portano dietro. Un'altra cosa molto comoda di AWK è che si possono concatenare fra loro variabili o costanti semplicemente scrivendoli uno dopo l'altro. Per esempio:

  nome = $1
  cognome = $2
  nominativo = nome " " cognome
  print "Nome e Cognome: " nominativo
Non ho pertanto le complicazioni tipiche del C come strcat, sprintf, atoi e cose del genere. Tutte le variabili sono stringhe e quindi non servono conversioni, se non quando sono usate nei calcoli aritmetici, ma in tal caso le fa AWK automaticamente. Ci sono ovviamente le istruzioni di controllo classiche del C: if, do, while, for, ecc. La loro sintassi è praticamente uguale. Stranamente non c'è l'istruzione switch, ma non se ne sente molto la mancanza visto che si possono usare i patterns, cosí come manca il goto ("considered harmful"). Le variabili non devono essere precedute da $ come succede in shell, perl ed altri linguaggi interpretati, con l'eccezione delle variabli $0,$1,ecc. Le stringhe costanti devono pertanto essere sempre racchiuse fra doppi apici, a meno che non siano dei numeri. Una cosa importante da ricordare è che tutti gli indici in AWK partono da 1 e non da 0 come si usa in C. In generale una istruzione sta su una sola riga. È però possibile mettere più istruzioni in una riga separandole con un punto e virgola, oppure scrivere un' istruzione su più righe utilizzando il carattere backspace (\) per concatenarle fra di loro.

Il linguaggio di AWK comprende alcune istruzioni molto potenti per leggere e scrivere da files o da pipes su comandi esterni. Fra queste ricordiamo la printf, il cui uso è molto simile a quello del C:

  printf("Nome e Cognome: %-24s\tEtà: %2d\n", nominativo, eta)
e la print che si limita a stampare i valori specificati concatenandoli con la variabile OFS (output field separator) e terminando il tutto con un newline:
  OFS = "\t"
  print "Nome e Cognome: " nominativo, "Età: " eta
Notare che nell'esempio i valori passati alla print sono due e non quattro perché "Nome e Cognome: " e nominativo sono concatenati in un unico valore, cosi come "Età: " ed eta. I due valori sono stampati in output separati da OFS, precedentemente settato a Tab.

Possiamo ovviamente leggere e scrivere in files esterni:

  outfile = "output.txt"
  print $1,$2 > outfile
  print $1,$2 >> "/tmp/xxx.log"	# notare gli apici attorno al nome
  getline < "input.txt"		# assegna NF, $0 e $1 ... $N
  getline my_var < "input.txt"	# assegna la variabile my_var
Possiamo inoltre scrivere in un pipe connesso allo standard input di un programma esterno o leggere l'output di un programma da un pipe:
  print $0  | "mail -s test " destinatario
  print "." | "mail -s test " destinatario
  close("mail -s test " destinatario)

  "hostname" | getline hostname
  close("hostname")
Notare che alla fine è necessario chiudere i files e che questi vengono referenziati con il loro pathname o con il comando unix eseguito. Pertanto l'espressione close("mail -s test " destinatario) chiude il pipe che è stato aperto in precedenza con tale comando.

Gli array associativi

Una cosa molto comoda che non si trova in C e che invece è disponibile in AWK è la possibilità di gestire in modo molto semplice degli array associativi, cioè delle strutture dati in cui posso associare un valore ad una chiave arbitraria e recuperarlo in maniera molto efficiente. Per esempio posso contare quante volte ogni parola compare nei dati di input con il seguente programmino:

  #!/usr/bin/awk -f
  { for (i=1; i<=NF; i++) totale[$i]++ }
  END { for (parola in totale) print parola, totale[parola] }
Due righe di AWK che si buttano giù in meno di un minuto. Provate a riscriverlo in C e controllate quanto codice dovete scrivere e quanto tempo ci avrete messo a farlo funzionare. Nell'esempio ho utilizzato un array associativo totale che contiene in corrispondenza di ciascuna parola letta in input il numero di volte che la parola è stata trovata. Nell'azione corrispondente al pattern END ho utilizzato una particolare sintassi dell'istruzione for che assegna in sequenza la variabile parola a tutte le chiavi contenute nell'array e stampa la chiave ed il valore ad essa associato. Posso anche verificare se una certa chiave è presente in un array con la sintassi:
  if ("chiave" in array) ...
Posso infine cancellare un elemento o l'intero array con l'istruzione delete:
  delete array["pippo"]
  delete array
Le differenze sostanziali rispetto agli array tradizionali del C sono che non devo preallocare l'array con una certa dimensione, in AWK tutta la gestione della memoria è automatica, e che al posto degli indici numerici ho delle chiavi di accesso costituite da stringhe. Pertanto non farò più riferimento all'elemento con posizione 123 ma a quello con chiave alfanumerica "123" oppure "pippo". Se devo comunque usare indici numerici lo posso fare lo stesso ma di fatto sto sempre utilizzando chiavi alfanumeriche, per cui l'espresssione array[123] è in realtà equivalente a array["123"]. Posso anche simulare array multidimensionali con la notazione array[x,y,z].

I patterns

Abbiamo visto che un programma AWK è costituito da una serie di coppie pattern-azione, in cui l'uno o l'altro possono essere omessi. Un pattern può essere costituito da:

/espressione regolare/
il pattern risulta vero per tutte le righe che soddifano l'espressione regolare in questione

espressione
una qualsiasi espressione C risulta vera se il suo risultato finale è diverso da zero e dalla stringa vuota.

BEGIN e END
due particolari pattern che risultano veri rispettivamente all'inizio ed alla fine dei dati di input. Possono essere usati per eseguire delle azioni di inizializzazione o di chiusura del programma.

pattern vuoto
un pattern vuoto, cioè mancante, è soddisfatto da qualsiasi riga di input e pertanto la corrispondente azione viene sempre eseguita, a meno che una delle azioni precedenti decida di saltare al record successivo.

pattern1,pattern2
una coppia di pattern risulta soddisfatta per il gruppo di record compresi fra quello che soddisfa il primo pattern e quello che soddisfa il secondo, estremi inclusi.
È possibile che una riga di input soddisfi più di un pattern. In questo caso vengono eseguite tutte le azioni ad essi corrispondenti nell'ordine in cui sono stati specificati. È però possibile terminare in un qualsiasi momento l'elaborazione del record corrente senza esaminare ed eseguire i pattern seguenti utilizzando l'istruzione next che salta direttamente al record successivo.

Le espressioni regolari

Per spiegare bene le espressioni regolari ci vorrebbe un'intero articolo, pertanto assumo che già le conosciate almeno a grandi linee e cercherò di farvi vedere come si possono usare con AWK.

Posso usare un'espressione regolare per confrontare l'intera riga di input oppure un singolo campo utilizzando l'operatore ~:

  #!/usr/bin/awk -f
  /^From: /       { print "Mittente: " $2 }
  $1 ~ /Subject:/ { $1 = "Soggetto:"; print } 
Posso anche usare un'espressione regolare come argomento ad una delle varie funzioni che accettano espressioni regolari come parametri, per esempio:
  if (match($1, /Microsoft/) {
      gsub(/Microsoft/, "Micro$$$oft", $1)
  }

Le funzioni built-in

Il linguaggio di AWK contiene un buon numero di funzioni built-in predefinite, per esempio funzioni numeriche, funzioni per lavorare con stringhe, funzioni di I/O, funzioni per formattare le date, ecc. Fra le più utili possiamo ricordare:

match(string, regexp)
ritorna la posizione nella stringa dove è stato trovato un testo che soddisfa l'espressione regolare.

sub(regexp, repl [,var])
sostituisce il valore repl all'espressione regolare regexp nella variabile var oppure in $0. Esiste anche una gsub che fa la stessa cosa ma per tutte le occorrenze di regexp

substr(stringa, pos [,len])
ritorna la sottostringa a partire dal carattere pos della stringa e lunga al massimo len, se specificato

split(stringa, array [,regexp])
spezza la stringa in una serie di elementi in corrispondenza di una espresssione regolare, li assegna agli elementi dell'array array[1] ... array[N] e restituisce il numero di elementi trovati

system(comando)
esegue un comando unix esterno e restituisce il suo codice di ritorno
Ne esistono ovviamente molte altre che non è possibile illustrare qui per mancanza di spazio.

Una cosa abbastanza facile da fare con AWK è un filtro che spia tutto quello che viene scritto in un file di log e calcola delle statistiche, o dei totali oppure esegue dei comandi quando trova certi messaggi di errore. Per esempio:

  tail -f /var/log/messages \
  | awk '($5 ~ "rshd" && $7 ~ "root") { system("mail -s 'ROOT RSH' root") }'
In questo modo posso implementare esternamente delle funzionalità che un certo programma non è in grado di fornire, o monitorare il verificarsi di errori o di condizioni critiche ed intraprendere automaticamente delle azioni. Il tutto senza dover modificare il programma che viene monitorato che si limita semplicemente a scrivere il suo file di log.

Le funzioni definite dall'utente

AWK permette all'utente di definire delle proprie funzioni che possono poi essere utilizzate liberamente all'interno del codice esattamente come quelle predefinite. La sintassi per definire nuove funzioni è la seguente:

  function nome(parametri) {
      ... body ...
  }
Per esempio posso definire il classico fattoriale con:
  function fact(n) {
      if (n <= 1) {
	  return(1)
      } else {
          return (n * fact(n-1))
      }
  }
e poi utilizzarlo in una regola o in un'altra funzione:
  $1 ~ "^[0-9]+$" {
      m = fact($1)
  }
Non è possibile dichiarare variabili locali all'interno delle funzioni, ma si può aggirare questo limite dichiarando degli argomenti in piu rispetto a quelli che vengono passati. In questo modo quelli che non sono specificati nella chiamata sono inizializzati con stringhe vuote e possono essere usati come variabili locali. Se nella funzione fact avessi bisogno di due variabili locali potrei pertanto scrivere:
  function fact(n,	var1, var2) {
      var1 = ...
      var2 = ...
      if (n <= 1) {
	  return(1)
      } else {
          return (n * fact(n-1))
      }
  }
Notate che esiste la convenzione di separare gli argomenti locali dai parametri con degli spazi in più, per migliorare la leggibilità del codice, come nell'esempio precedente.

Come richiamare AWK

Esistono vari modi di modi di utilizzare AWK, da solo o in combinazione con altri programmi. È possibile eseguirlo semplicemente dal prompt delle shell passandogli lo script nella linea di comando, se non è troppo lungo:

  awk '/pippo/ { print $1 }' input-file.txt
oppure memorizzando il programma in un file esterno:
  awk -f pippo.awk input-file.txt
Se questo file viene reso eseguibile e contiene nella prima riga il path di AWK preceduto da #! è possibile anche eseguirlo direttamente col suo nome:
  pippo.awk input-file.txt
Posso anche inserire il comando awk e il suo script all'interno di uno script di shell, eventualmente utilizzando la sostituzione della shell all'interno dello script AWK:
  #!/bin/bash
  ...
  find . -name \*.c | awk '
      # programma awk
      BEGIN { ... }
      ($1 == "xyz") { ... }
  ' | sort | uniq
  ...
Il vantaggio di questa tecnica è che lo script di shell e gli script di AWK che gli servono sono contenuti nello stesso file. In questo caso è pero' necessario quotare l'intero script di AWK all'interno dello script di shell. Se all'interno dello script non ci sono apici singoli conviene usare questo carattere, altrimenti si è costretti a usare i doppi apici ma in tal caso bisogna ricordarsi di quotare tutti i dollari ed i backslash dello script lasciando solo quelli che devono essere espansi dalla shell.

Alcuni esempi più o meno triviali

AWK viene usato molto di frequente per fare operazioni 'triviali' sui dati di input, cose che spesso potrei fare anche utilizzando cat, grep o sed. Molto spesso si tratta di progammi di una sola riga. Vediamo qualche esempio.

Un esempio da non imitare

Tempo fa sono stato costretto (per vile denaro) a scrivere un programmino in msdos (ORRORE!) per interfacciarmi ad una applicazione unix. Non disponendo nè di msdos nè di un compilatore C per tale S.O. (Schifezza Obbrobriosa), ho deciso di sviluppare il codice in Linux con AWK e poi portare il tutto in dos utilizzando la versione dos di AWK. Ne è venuto fuori un semplice programma interattivo che funziona più o meno cosí:

  #!/usr/bin/gawk -f
  BEGIN {
      ESCAPE = "^["
      inizializzazione()
      show_menu()
      prompt()
  }

  END {
      cls()
      print "Bye."
  }

  ($1 == "q" || $1 == "quit") {
      exit
  }

  ($1 == "1") {
      do_comando1()
      show_menu()
      prompt()
      next
  }

  ...

  {
      show_menu()
      message("\007comando sconosciuto")
      prompt()
      next
  }

  function inizializzazione() {
      ...
  }

  function do_comando1() {
      ...
  }

  function show_menu() {
      cls();
      cursor(2,1); printf("1.\tComando 1")
      ...
  }

  function message(msg) {
      cursor(25,1); kill_line()
      printf msg
  }

  function prompt() {
      cursor(24,1); kill_line()
      printf("comando ==> ")
  }

  function cls() {
      printf(ESCAPE "[2J")
      printf(ESCAPE "[1;1H")
  }

  function cursor(row, col) {
      printf(ESCAPE "[" row ";" col "H")
  }

  function kill_line() {
      printf(ESCAPE "[K")
  }
In pratica ho sfruttato il linguaggio di AWK per disporre di uno pseudo-C interpretato sotto dos, e utilizzando le sequenze standard di escape ANSI, che per fortuna ci sono anche in dos, ho scritto un semplicissimo programmino che legge i comandi interattivi dell'utente dallo standard input, li esegue e stampa di nuovo il menu e il prompt. Questo è un uso abbastanza improprio di AWK, che ricordo essere stato progettato per filtrare testi, ma mostra come esso sia abbastanza flessibile da poter essere utilizzato anche per realizzare dei semplici programmi interattivi.

AWK e Perl

Un altro linguaggio molto diffuso che si può usare in alternativa ad AWK è il Perl. In realtà sono due strumenti abbastanza diversi anche se possono essere usati per fare cose simili. Perl e' un generico linguaggio di programmazione con molte funzionalità in più ed una ricca libreria di moduli. AWK è un tool per scrivere filtri dotato di un linguaggio con sintassi simile al C. Il vantaggio di Perl è che è un linguaggio molto più completo di AWK, per cui si possono fare cose che con AWK non sono possibili. Lo svantaggio di Perl è che il suo linguaggio di programmazione è un po' più complicato e meno leggibile, e questo può essere un problema specialmente per i principianti. Il vantaggio di AWK è che il suo linguaggio di programmazione è molto più 'pulito' e semplice da usare di quello di Perl. Inoltre AWK gestisce automaticamente la lettura dei dati e la separazione dei campi.

In linea generale conviene usare AWK quando si devono realizzare filtri di testo e non si ha bisogno delle funzionalità extra offerte da Perl. Conviene invece usare Perl se si devono scrivere programmi che non sono dei filtri, per esempio script di amministrazione di sistema o cgi, oppure cose che necessitano della potenza in più offerta da Perl. Esiste comunque un traduttore che è grado di tradurre in Perl i programmi scritti per AWK.


In conclusione, se conoscete AWK avete a disposizione nella vostra cassetta degli attrezzi uno strumento abbastanza facile da usare ma anche abbastanza potente per risolvere con facilità un gran numero di problemi che si incontrano quotidianamente quando si lavora in unix. Il tempo e la fatica che vi risparmierete utilizzando AWK vale sicuramente il paio di mezze giornate che spenderete a leggervi la pagina di manuale (man gawk) o l'ottimo file di info disponibile in emacs. Se poi conoscete già il C gran parte della fatica è già fatta. Un ulteriore vantaggio di AWK è che è disponibile in tutti i sistemi operativi e perfino in ambiente MSDOS. Potete quindi portare facilmente il vostro codice da un sistema all' altro e riutilizzarlo senza problemi.

di Massimo Dal Zotto


B
[precedente] Creare CD - Copertina - Giochi [successivo]