awkIniziare con awk


Osservazioni

Il nome AWK deriva dalle ultime iniziali dei suoi creatori Alfred V. Aho, Peter J. Weinberger e
Brian W. Kernighan.

risorse

Versioni

Nome Versione iniziale Versione Data di rilascio
POSIX awk 1992 IEEE Std 1003.1, edizione 2013 2013/04/19
Un awk vero awk o nawk o BWK 198X - 2012/12/20
GNU awk o gawk 1986 4.1.3 2015/05/19

AWK con esempi

AWK è un linguaggio di manipolazione delle stringhe, utilizzato in gran parte nei sistemi UNIX. L'idea alla base di AWK era di creare un linguaggio versatile da utilizzare quando si lavorava sui file, che non era troppo complesso da comprendere.

AWK ha alcune altre varianti, ma il concetto principale è lo stesso, solo con funzionalità aggiuntive. Queste altre varianti sono NAWK e GAWK. GAWK contiene tutte le funzionalità di entrambi, mentre NAWK è un gradino sopra AWK, se lo desideri.

Il modo più semplice per pensare a AWK è considerare che ha 2 parti principali. Il modello e l'azione.

Probabilmente l'esempio più semplice di AWK: (Vedi anche: Hello World)

BEGIN {print "START"}
      {print        }
END   {print "STOP" }
 

Qui, le parole chiave BEGIN e END sono il modello, mentre l'azione è all'interno di {}. Questo esempio sarebbe inutile, ma richiederebbe solo piccole modifiche per renderlo veramente utile.

BEGIN {print "File\tAuthor"}
      {print $8, "\t", $3}
END {print " - DONE - "}
 

Qui, \t rappresenta un carattere di tabulazione e viene utilizzato per aumentare i limiti della linea di output. $ 8 e $ 3 sono simili all'uso che si vede in Shell Scripts , ma invece di usare il 3 ° e l'8 ° argomento, usa la 3a e l'8a colonna della riga di input.

Quindi, questo esempio dovrebbe stampare: File Autore nella riga superiore, mentre la seconda riga ha a che fare con i percorsi dei file. $ 8 è il nome del file, $ 3 è il proprietario (quando si guarda il percorso della directory, questo sarà più chiaro). Infine, la linea di fondo verrebbe stampata, come ci si aspetterebbe - FATTO -

Il credito per l'esempio precedente va a http://www.grymoire.com/Unix/Awk.html

File di riferimento

coins.txt di Greg Goebel:

gold     1    1986  USA                 American Eagle
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona
silver  10    1981  USA                 ingot
gold     1    1984  Switzerland         ingot
gold     1    1979  RSA                 Krugerrand
gold     0.5  1981  RSA                 Krugerrand
gold     0.1  1986  PRC                 Panda
silver   1    1986  USA                 Liberty dollar
gold     0.25 1986  USA                 Liberty 5-dollar piece
silver   0.5  1986  USA                 Liberty 50-cent piece
silver   1    1987  USA                 Constitution dollar
gold     0.25 1987  USA                 Constitution 5-dollar piece
gold     1    1988  Canada              Maple Leaf
 

Teoria minimale

Generalità awk one-liner:

awk <awk program> <file>
 

o:

<shell-command> | awk <awk program> 
 

<shell-command> e <file> sono indirizzati come input awk .

<awk program> è un codice che segue questo modello (singolo, non doppio, virgolette):

'BEGIN   {<init actions>};
 <cond1> {<program actions>};
 <cond2> {<program actions>};
 ...
 END  {<final actions>}'
 

dove:

  • <condX> condizione <condX> è molto spesso un'espressione regolare /re/ , da abbinare alle linee di input di awk;
  • <* actions> sono sequenze di istruzioni , simili ai comandi della shell, dotate di costrutti simili a C.

`` viene elaborato secondo le seguenti regole:
  1. BEGIN ... ed END ... sono opzionali ed eseguiti prima o dopo l'elaborazione delle righe di input di awk.
  2. Per ogni riga nell'input awk, se la condizione <condN> è meat, viene eseguito il relativo blocco <program actions> .
  3. {<program actions>} impostazione predefinita {print $0} .

Le condizioni possono essere combinate con operatori logici standard:

    /gold/ || /USA/ && !/1986/
 

dove && ha la precedenza su || ;

La dichiarazione di print print item1 item2 statement stampa gli articoli su STDOUT.
Gli elementi possono essere variabili ( X , $0 ), stringhe ("ciao") o numeri.
item1, item2 vengono confrontati con il valore della variabile OFS ;
item1 item2 sono justapoxed ! Usa item1 " " item2 per spazi o printf per più funzioni.

Le variabili non hanno bisogno di $ , cioè: print myVar;
Le seguenti variabili speciali sono integrate in awk:

  • FS : funge da separatore di campo per dividere le linee di input di awk nei campi. Posso essere un singolo personaggio, FS="c" ; una stringa nulla, FS="" (quindi ogni singolo carattere diventa un campo separato); un'espressione regolare senza barre, FS="re" ; FS=" " sta per le corse di spazi e tab e il valore di default.
  • NF : il numero di campi da leggere;
  • $1 , $2 , ...: 1 ° campo, 2 ° campo. ecc. della linea di ingresso corrente,
  • $0 : linea di input corrente;
  • NR : numero della linea attuale.
  • OFS : stringa per fascicolare i campi quando stampati.
  • ORS : separatore dei record di output, per impostazione predefinita una nuova riga.
  • RS : Separatore della riga di input (registrazione). Il valore predefinito è newline. Imposta come FS .
  • IGNORECASE : influisce su FS e RS quando sono espressione regolare;

Esempi

Filtra le linee con regexp gold e contale:

# awk 'BEGIN {print "Coins"} /gold/{i++; print $0}  END {print i " lines out of " NR}' coins.txt
Coins
gold     1    1986  USA                 American Eagle      
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona 
gold     1    1984  Switzerland         ingot 
gold     1    1979  RSA                 Krugerrand 
gold     0.5  1981  RSA                 Krugerrand 
gold     0.1  1986  PRC                 Panda                       
gold     0.25 1986  USA                 Liberty 5-dollar piece
gold     0.25 1987  USA                 Constitution 5-dollar piece
gold     1    1988  Canada              Maple Leaf
9 lines out of 13
 

Default print $0 azione e condizione basata sulla variabile di awk interna NR :

# awk 'BEGIN {print "First 3 coins"} NR<4' coins.txt
First 3 coins                                                  
gold     1    1986  USA                 American Eagle         
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona 
silver  10    1981  USA                 ingot
 
Formattazione con `printf` in stile C:
# awk '{printf ("%s \t %3.2f\n", $1, $2)}' coins.txt
gold     1.00                                      
gold     1.00                                      
silver   10.00                                     
gold     1.00                                      
gold     1.00                                      
gold     0.50                                      
gold     0.10                                      
silver   1.00                                      
gold     0.25                                      
silver   0.50                                      
silver   1.00                                      
gold     0.25                                      
gold     1.00
 

Esempi di condizioni

awk 'NR % 6'            # prints all lines except those divisible by 6
awk 'NR > 5'            # prints from line 6 onwards (like tail -n +6, or sed '1,5d')
awk '$2 == "foo"'       # prints lines where the second field is "foo"
awk '$2 ~ /re/'         # prints lines where the 2nd field mateches the regex /re/
awk 'NF >= 6'           # prints lines with 6 or more fields
awk '/foo/ && !/bar/'   # prints lines that match /foo/ but not /bar/
awk '/foo/ || /bar/'    # prints lines that match /foo/ or /bar/ (like grep -e 'foo' -e 'bar')
awk '/foo/,/bar/'       # prints from line matching /foo/ to line matching /bar/, inclusive
awk 'NF'                # prints only nonempty lines (or: removes empty lines, where NF==0)
awk 'NF--'              # removes last field and prints the line
 

Aggiungendo un'azione {...} si può stampare un campo specifico, piuttosto che l'intera linea, ad esempio:

awk '$2 ~ /re/{print $3 " " $4}'
 

stampa il terzo e il quarto campo di linee in cui il secondo campo inserisce la regex / re /.

Alcune funzioni di stringa

substr() :

# awk '{print substr($3,3) " " substr($4,1,3)}' 
86 USA                                            
08 Aus                                            
81 USA                                            
84 Swi                                            
79 RSA                                            
81 RSA                                            
86 PRC                                            
86 USA                                            
86 USA                                            
86 USA                                            
87 USA                                            
87 USA                                            
88 Can                                            
 

match(s, r [, arr]) restituisce la posizione in s cui si verifica la regex r e imposta i valori di RSTART e RLENGTH . Se viene fornito l'argomento arr , restituisce l'array arr cui gli elementi sono impostati sulla sottoespressione parentesi associata. Le partite dell'elemento 0 di arr sono impostate sull'intera corrispondenza delle espressioni regolari. Anche le espressioni arr[n, "start"] e arr[n, "length"] forniscono la posizione iniziale e la lunghezza di ciascuna sottostringa corrispondente.

Altre funzioni per le stringhe:

sub(/regexp/, "newstring"[, target])
gsub(/regexp/, "newstring"[, target])
toupper("string")
tolower("string")
 

dichiarazioni

Una semplice affermazione è spesso una delle seguenti:

variable = expression 
print [ expression-list ] 
printf format [ , expression-list ] 
next # skip remaining patterns on this input line
exit # skip the rest of the input
 

Se stat1 e stat2 sono dichiarazioni, le seguenti sono anche istruzioni:

{stat}

{stat1;  stat2}

{stat1 
stat2}

if ( conditional ) statement [ else statement ]
 

I seguenti costrutti C-like standard sono dichiarazioni:

if ( conditional ) statement [ else statement ]
while ( conditional ) statement
for ( expression ; conditional ; expression ) statement
break    # usual C meaning 
continue # usual C meaning 
 

Un ciclo in stile C per stampare l'elemento di descrizione della lunghezza variabile, iniziando dal campo 4:

# awk '{out=""; for(i=4;i<=NF;i++){out=out" "$i}; print out}' coins.txt
USA American Eagle                    
Austria-Hungary Franz Josef 100 Korona
USA ingot                             
Switzerland ingot                     
RSA Krugerrand                        
RSA Krugerrand                        
PRC Panda                             
USA Liberty dollar                    
USA Liberty 5-dollar piece            
USA Liberty 50-cent piece             
USA Constitution dollar               
USA Constitution 5-dollar piece       
Canada Maple Leaf
 

Si noti che i è inizializzato a 0.

Se le condizioni e i calcoli sono applicati ai campi nuneric:

# awk '/gold/ {if($3<1980) print $0 "$" 425*$2}' coins.txt    
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona      $425
gold     1    1979  RSA                 Krugerrand                  $425   
 

Script eseguibile AWK

#!/usr/bin/gawk -f
# This is a comment
(pattern) {action}
...
 

Passando le variabili della shell

# var="hello"
# awk -v x="$var" 'BEGIN {print x}'
hello
 

Ciao mondo

L'esempio Hello world è semplice come:

awk 'BEGIN {print "Hello world"}'
 

Il programma awk più basilare consiste in un valore vero (tipicamente 1 ) e fa awk echo il suo input:

$ date | awk '1'
Mon Jul 25 11:12:05 CEST 2016
 

Dal momento che "Hello World" è anche un vero valore, potresti anche dire:

$ date | awk '"hello world"'
Mon Jul 25 11:12:05 CEST 2016
 

Tuttavia, la tua intenzione diventa molto più chiara se scrivi

$ date | awk '{print}'
Mon Jul 25 11:12:05 CEST 2016
 

anziché.

Come eseguire i programmi AWK

Se il programma è breve, puoi includerlo nel comando che esegue awk:

awk -F: '{print $1, $2}' /etc/passwd
 

In questo esempio, utilizzando l'opzione della riga di comando -F: ti consigliamo di usare awk: come delimitatore dei campi di input. È lo stesso come

awk 'BEGIN{FS=":"}{print $1,$2}' file
 

In alternativa, possiamo salvare l'intero codice awk in un file awk e chiamare questo programma awk in questo modo:

awk -f 'program.awk' input-file1 input-file2 ...
 

program.awk può essere qualsiasi programma multilinea, ovvero:

# file print_fields.awk
BEGIN {print "this is a header"; FS=":"}
{print $1, $2}
END {print "that was it"}
 

E poi eseguirlo con:

awk -f print_fields.awk /etc/passwd   #-f advises awk which program file to load
 

O più in generale:

awk -f program-file input-file1 input-file2 ...
 

Il vantaggio di avere il programma in un file separato è che puoi scrivere il programma con l'identificazione corretta per avere un senso, puoi includere commenti con #, ecc.