Community
 
Aggiungi lista preferiti Aggiungi lista nera Invia ad un amico
------------------
Crea
Profilo
Blog
Video
Sito
Foto
Amici
   
 
 

2.5        AWK

Linguaggio per trattamento di file sequenziali (1977,1985)

Il nome deriva dalle iniziali dei suoi tre autori (Alfred V. Aho, Peter J. Weinberger, e Brian W. Kernighan). La versione originale nasce agli AT&T Bell Laboratories nel 1977; nel 1985 diventa disponibile, sui sistemi UNIX, una versione più potente con funzioni definibili dall'utente, più fili in input e trattamento delle espressioni regolari.

AWK è indicato per la manipolazione di file sequenziali e per la generazione di stampe; l'interprete gestisce automaticamente l'input ed applica, ad ogni riga di questo, le regole indicate dal programma, per stabilire se questa deve essere scartata, riscritta o modificata. Le regole hanno la forma:

pattern {comando}

dove pattern è una stringa di testo, una condizione o un'espressione regolare: se la riga contiene, il testo, o soddisfa la condizione o l'espressione regolare, è inviata in output se omesso {comando}, altrimenti è eseguito {comando}. Viceversa se manca pattern si esegue {comando}.

La struttura generale di un programma AWK è:

§   regole iniziali (pattern BEGIN)

§   regole applicate ad ogni riga del file di input

§   operazioni finali (pattern END)

Il trattamento dei files è facilitato da un insieme di variabili mantenute dall'interprete: $0 è la riga, $1, $2,… sono i campi della riga, NF è il numero campi nella riga, NR il numero di righe totali, ed altri ancora.

AWK è molto semplice da utilizzare: poiché nella riga di comando si può inserire il "programma", è facile scrivere cose del tipo:

awk '/cpu_time/ {print NR " " $0}' flin

per estrarre dal file flin le righe contenenti cpu_time, indicandone la posizione nel file.

L'esempio seguente realizza la fusione di due file ordinati; la posizione della chiave è la sua lunghezza sono fornite sulla riga di comando (opzioni –v, l'opzione –f introduce lo script AWK):

awk -f merge.awk -v inizio=45 -v lungo=12 flon flin

# GNU Awk 3.0.6

# Il programma fonde due file

#

func take_key(riga) { return sprintf("0%s",substr(riga,inizio,lungo))}

 

func read2() { if ((getline Rec2 < file2) > 0)

                 return take_key(Rec2)

               else

                 return "9"

             }

 

func compare() {while (1 == 1) {

                if (Key1 == Key2) {

                  if (Key1 == "9")

                    break

                }

                if (Key1 < Key2) break

                print Rec2

                Key2 = read2()

                Ck2++

              }

           }

 

BEGIN { print "Inizio fusione"

       file2 = ARGV[2]

       ARGV[2]= "" # il secondo file e' gestito da programma

       print "Chiave a colonna " inizio "  lunga " lungo "\n"

       Key2 = read2()

      }

# corpo del programma

  {

   Key1 = take_key($0)

   compare()

   print $0

  } 

 

END { Key1 = "9"

      compare()

      printf ("\nTotale righe %d (%d + %d)", NR + Ck2, NR, Ck2)

      print "\nFine fusione"}

Le chiavi di input del programma sono:

a.out

a.exe

demounit.gpi

gpc.pas

help.bat

pexecute.pas

prova.pas

unit.txt

flin

flon

merge.awk

p.bat

L'output del programma è:

Inizio fusione

Chiave a colonna 45  lunga 12

 

A        OUT       409,011  04-25-02 10:17p a.out

A        EXE       411,059  04-25-02 10:17p a.exe

DEMOUNIT GPI         4,299  04-25-02 10:17p demounit.gpi

FLIN                   434  05-15-02  6:11p flin

FLON                     0  05-15-02  7:52p flon

GPC      PAS        69,959  07-13-00  4:03a gpc.pas

HELP     BAT            13  05-13-02  6:34p help.bat

MERGE    AWK           956  05-15-02  7:50p merge.awk

P        BAT            58  05-15-02  7:39p p.bat

PEXECUTE PAS         3,887  05-13-02  6:45p pexecute.pas

PROVA    PAS           201  04-25-02 10:17p prova.pas

UNIT     TXT         2,105  04-25-02 10:23p unit.txt

 

Totale righe 12 (4 + 8)

Fine fusione

L'esempio seguente illustra l'utilizzo di AWK per semplificare la scrittura di programmi Brianf (v. par. 2.7) tramite alcune macrofunzioni e l'utilizzo di nomi simbolici per gli indirizzi di memoria.

# GNU Awk 3.0.6

# Macroassembler per Brianf

#

func sost(token) {

   if (token !~ id_regexp) return token;

   if (token in arr_var) return arr_var[token];

   return arr_var[token] = indrz++;

}

func go(to) {

       if (to != "") {

         j = to - mem;

         if (j > 0)

           for (i = 1; i <= j; i++) printf (">");

         else if (j < 0)

           for (i = 0; i > j; i--) printf ("<");

         if (j != 0) mem = to;

        }

      }

func commento() {mtch=1;return sprintf(" \t# %s\n",row);} # commento

func clean(n) {if (n != "") go(n); printf("[-]")}

func incr(n) {go(n);printf("+");}

func decr(n) {go(n);printf("-");}

 

func move(from, to){

          go(from);printf("[-");go(to);printf("+");go(from);printf("]");go(to);

          }

BEGIN {

       id_regexp = "[A-Za-z][A-Za-z0-9]*";

       indrz = 1; # assegna indirizzi a nomi simbolici

       mem = 0;   # posizione di memoria

       mtch = 0;  # indica se trovata istruzione

      }

            {row = $0;$2 = sost($2);$3 = sost($3)} 

/INCR/      {incr($2);printf("%s",commento());}

/DECR/      {decr($2);printf("%s",commento());}

/MOVE/      {clean($3);move($2,$3);printf("%s",commento());}

/INPUT/     {go($2);printf(",%s",commento());}

/OUTPUT/    {go($2);printf(".%s",commento());}

/COPY/      {clean($3);clean("0");go($2);

             printf("[-");incr("0");incr($3);go($2);printf("]");

             move("0",$2);go($3);printf("%s",commento());}

/CLEAN/     {clean($2);printf("%s",commento());}

/GOTO/      {go($2);printf("%s",commento());}

            {if (mtch == 0) print $0; mtch = 0;}  # prende tutto il resto

 

END  {for (VAR in arr_var) printf ("\nVariabile %s \ta %s",VAR, arr_var[VAR]);}