Exemples d'utilisation de AWK
F. Balmas
mai 98 et octobre 99


AWK
appliquer une/des actions a toutes/certaines lignes d'un fichier
fichier
enregistrements (lignes) separees par des \n (RS)
formes de champs (colonnes) separees par des espaces (FS)



programme  == 	BEGIN { actions initiales }
	 	selecteur1 { action1 }
		selecteur2 { action2 }
		...
		END { actions finales }

syntaxe == gawk ' programme ' fichier
	   gawk -f fichier-programme fichier


Fichier pour les exemples ci-dessous :
Carnet
Durand Paul 0145464748
Dupond Anne 0123456789
Martin Bernard 0239485776
Durand Jacques 0234455667
Dupont Paul 0398877665
Bernard Alain 0293394884


Exemples de programmes simples


Action simple, pour tous les enregistrements
'{print}'		cat
'{ print $1 }'		afficher 1er mot de chaque ligne
'{ print $2, $1 }'	liste prenom-nom
	carnet
Selection simple
'/Dupond/'		afficher (action par defaut) les lignes contenant Dupond
'/Dupon/'		"" Dupon (--> donc 2 enregistrements !)
'/Bernard/'		Bernard comme nom OU prenom
Selection sur un champ
'$1 ~ /Bernard/'	nom de famille = Bernard
'$2 ~ /Bernard/'	prenom = Bernard
Selection - Action
'$1 ~ /Bernard/ { print $3 }'  	afficher le no telephone de nom=Bernard
'$2 ~ /Paul/ { print $1 }'	afficher nom famille des prenom=Paul
Selecteur avec expression reguliere
'/A-Z/'			lignes avec une majuscule
'/[A-L]/'		"" ds l'interval A-L
'$2 ~ /^[ABC]/'		prenom commencant par A, B ou C
'$3 ~ /^0[2-5]/'	habitant en province 
'/[Pp]aul/'		majuscule ou non
Exercices sur ER
un mot constitue uniquement de minuscules
	/^[a-z]+$/
un mot commencant par une maj. suivi de minuscules seulement
	/^[A-Z][a-z]+$/
un mot commencant par e et finissant par e
	- en min. seulement
	- en maj. ou en min.
/[A-Z]/
/^[A-Z]$/
/^0[12345]/
/jean/
/^jean/
/^jean$/
/[Jj]ean/
/^[Jj]ean/
/^[Jj]ean$/
Selecteur avec variables NR et NF
'NR==1{print}'		ligne 1
'NR<5'			lignes 1 a 4
'NR>5'			lignes 5 et ss
'NR%2==0 '		lignes paires
'NR%2==1'		lignes impaires
'NF>1'			lignes ou nb de mots > 1
Selection de blocs
'/struct/,/b/'		de ligne avec struct a ligne avec b
				event. plusieurs blocs
'NR==3,NR==6'		de ligne 3 a 6
Alternatives + Variables
'{ print NR, $0 }'		prefixe chaque ligne avec son numero d'ordre
'{ print NF, $0 }'		prefixe chaque ligne avec son nb de champs
END { print NR }
END { print NF }		--> erreur
'{ if (NR%2 == 0) print $0 }'	affiche les lignes de rang pair
'{x=x+NF}END{print x}'		affiche le nb de mots total
'/Jean/{x=x+1}END{print x}'	affiche le nb d'occurences de Jean

{ if (NF > max) max = NF }
END { print max }

BEGIN { min = 80 }
{ if (NF < min) min = NF }
END { print min }

BEGIN { max=0 }
{ if ($3 > max) max = $3 }
END { print max }		affiche le plus grand

BEGIN {min = 99}
{ if ($3 < min) min = $3 }
END {print min}			affiche le plus petit
Boucles + Tableaux
 { i=1; while (i<=NF)		affichage des champs un a un
   { print $i, "|"; i++} }
 { printf ("%s %s ", $2, $1)
   for (i=3;i<=NF;i++) 
	printf ("%s ", $i)
   printf ("\n") }		inverse 1er et 2eme champ
 { for (i=NF;i>=1;i--) 
	printf ("%s ", $i)
   printf ("\n") }		inverse l'ordre des champs
 { file[NR]=$0 }
 END { for (i=NR;i>=1;i--)
		print file[i] }	affiche un fichier en ordre inverse
 { for (i=1;i<=NF;i++)
	mot[$i]=$i }
 END { for (i in mot)
	print i }		liste uniq des mots d'un fichier
 { for (i=1;i<=NF;i++)
	mot[$i]=mot[$i]+1 }
 END { for (i in mot)
	print i, mot[i]}	nb d'occurences de chaque mots


Caracteristiques avancees


Fonctions
'{ print foo($1) }
function foo(s)
{
         return length(s)
}'
Changement de FS
gawk 'BEGIN { FS=":" } { print $1 }' /etc/passwd

gawk 'BEGIN { FS=":"
              OFS = "|" }
      { print $1, $2, $3, $4, $5, $6, $7 }'   /etc/passwd

Pseudo tableaux a deux dimensions (indices multiples)
'{ for (i=1 ; i<=NF ; i++)
       mot[NR,i] = $i
}
END { for (m in mot)
	  print m, mot[m]   #  m = nombre caractere mot  (caractere bizzare !)
      print mot[1]    # ne fait rien
}'

Chargement de librairies
gawk -f round.awk -f prog file2
      programme dans ./prog, round.awk dans /usr/local/share/awk/

gawk -f ../Programs/Lib/passwd-sgi.awk --source '{ print getpwnam($1) }' file
Librairies et programme in-line
gawk -f round.awk --source '{ print $1 "arrondi = ", round($1) }' file2
      programme sur la ligne de commande
gawk -f round.awk '{ print $1 "arrondi = ", round($1) }' file2
      ERREUR
Variables ARGC et ARGV
gawk -f round.awk --source 'BEGIN {
     print ARGC
     for (i=0 ; i<= ARGC ; i++)
	 print i, ARGV[i]
     }
{ print $1 "arrondi = ", round($1) }' file2
--> 2
--> 0 gawk
--> 1 file2
Multiples blocks BEGIN, END et multiples fichiers
gawk 'BEGIN{ print "debut1" }
{ print $1 }
BEGIN{ print "debut2" }
END { print "fin" }
{ print $0}
END { print NR }' file file2
--> debut1 
    debut2
    $1		de chaque ligne des 2 fichiers
    $0			  ""
    fin
    nb de lignes total
Modification des champs
gawk '{ $1 = $2
     print $0  }' file

Fichier Awk executable
prog:
#!/bin/gawk
{ print $1}

prog file
     ERREUR,  ./prog  parse error, unterminated regexp

#!/bin/gawk -f
{ print $1}

prog file
 	affiche le 1er mot de chaque ligne de file
Appel a Shell et passage d'arguments
gawk '{ print NR
     system("affiche " NR) }' file
affiche:
	echo $1
 Pipes de commandes shell
gawk 'BEGIN{ FS=":" }{ print $1 | "sort" }' /etc/passwd
      affiche les noms d'utilisateurs tries
      l'affichage est redirige vers un pipe, puis la cmd shell est ececutee

gawk '{ print $1 | "sort | uniq" }' file3
      affiche les mots de la 1ere colonne, un seul de chaque sorte
      
gawk 'BEGIN { while ("cat file" | getline) print $2, $1 }'
      lit le fichier "file" ligne a ligne et le traite 
      execute la cmd shell et pipe le resultat en fichier d'entree pour Awk

gawk 'BEGIN { cmd = "cat " ARGV[2]
	print cmd }
$1 ~ "merci" { foo(cmd) }
function foo(c)
{
        while(c | getline)  {
		    print $1
	      }
}' file dico


Programmes exemples


Tri d'un fichier
ex. tri par insertion (Poly HW)
{ ligne[NR] = $0 }
END { 	sort( ligne , NR ) 
	for (i=1 ; i<=NR ; i++) print ligne[i]  }
function sort ( tab, n, i, j, tmp )
{
   for ( i=2 ; i<=n ; i++ )
   {
	j=i
	tmp = tab[i]
	print i,j
	while ( tmp < tab[j-1] )
	{
	   tab[j] = tab[j-1]
	   j--
	}
	tab[j] = tmp
   }
}
Renumerotation des comptes utilisateurs
gawk 'BEGIN { FS=":"; OFS=":"; no=1 }
{ print $1, $2, no++, $4, $5, $6, $7 }' /etc/passwd
Calcul du nombre de voyelles dans les mots d'un texte
'BEGIN {voy["a"]="a"; voy["e"]="e"; voy["i"]="i"; voy["o"]="o"; voy["u"]="u"
        for (v in voy)
            print v, voy[v]
 }
{ print $1, foo($1) }
function foo(s)
{
   nbv=0;     # ou variable comme parametre supplementaire
   split(s,a,"")
   for (p in a) {
       i=a[p]
       if (voy[i]==i) {  # ou if (i in voy)
          nbv++;
          }
       }
   return nbv
}'
A noter :
guillemets pour chaines ou caracteres
variables sont globales
tentative d'acces a un tableau creee l'entree dans le tableau
conversion string --> array(1)=1er caractere