Un pense-bête

Trucs de geek : la commande awk

Cet article vous présentera ce que l'on peut faire avec la commande AWK.

Pour utiliser awk vous devez passer 3 choses à cette commande :

  1. la sélection que vous souhaitez réaliser sur les lignes du fichier que vous traitez
  2. le traitement que vous réaliser sur ces lignes
  3. le nom du fichier à traiter

Dans la version la plus simple on va se contenter d'afficher le contenu d'un fichier. Il n'y aura donc pas de sélection. Cela va ressembler à cela :

$ awk '//{print}' /etc/passwd

La partie "//" signifie pas de sélection et la partie traitement entre les parathèses réalise un simple affichage (print) de la ligne en cours de traitement.

Si maintenant on ne veut afficher les lignes de ce fichier pour les seuls utilisateurs dont le nom contient "avahi" on ajoute le critère de sélection à la commande précédente :

$ awk '/avahi/{print}' /etc/passwd

Autre exemple :

$ awk '/localhost/{print}' /etc/hosts

donne :

127.0.0.1 localhost
::1     ip6-localhost ip6-loopback

Pour la sélection il est possible d'utiliser des caractères génériques :

  1. le point qui signifie 1 caractère. Donc "l.c" signifie une suite optionnel de caractères suiv d'un "l" puis d'un carctère puis d'un "c" puis éventuellement d'une suite de caractères.
  2. l'étoile qui signifie  0 ou plusieurs caractères. Ainsi "l*c" siginfie  une suite optionnel de caractères suiv d'un "l" puis d'une suite de caractère optionnelle puis d'un "c" puis éventuellement d'une suite de caractères.

Pour sélectionner vous pouvez utliiser des crochets droits ([]) qui permettent de fournir une liste de caractères recherchés. Ainsi :

$ awk '/[la]/{print]/' /etc/hosts

renverra les lignes qui contiennent un "l" ou un "a".

Ces deux modes de sélection peuvent se suivre. Ainsi avec le fichier suivant :

Ko<brkk
kk
kO
ko
koa
dd

l'instruction suivante :

$ awk '/[kK]o/{print]/' test.txt

listera les lignes contenant "Ko" et  ko".

Pour les ensembles on retrouve de grands classiques :

  1. [a-z] pour les minuscules
  2. [A-Z] pour les majuscules
  3. [0-9] pour les chiffres

On peut localiser l'endroit de la recherche en indiquant si l'expression doit commencer par ou finir par le critère de recherche. Ainsi

$ awk '/^K/{print]/' test.txt

liste les lignes qui commence par un K" :

Ko
KK
Kao

On peut localiser l'endroit de la recherche en indiquant si l'expression doit commencer par ou finir par le critère de recherche. Ainsi

$ awk '/^K/{print]/' test.txt

liste les lignes qui commence par un K" :

KK
Kao

Nous allons découvrir maintenant la partie traitement de l'instruction.

Soit le fichier test.txt

Ko 10 ddd
KK 200 ee
kk 5 fff

où les articles sont séparés par des tabulations. Dans ce cas il faut savoir que awk désigne par $1 la première zone, $2 la seconde et $3 la troisième. Ainsi l'instruction suivante :

$ awk '//{print $1 $2}' test.txt

donne

Ko10
KK200
kk5

Un truc important : si vous ajoutez une virgule entre les champs ils seront séparés. Ainsi :

$ awk '//{print $1, $2}' test.txt

donne 

Ko 10

KK 200

 

kk 5

On peut ajouter des caractères de séparation :

$ awk '//{print $1, "#", $2}' test.txt 

donne

Ko # 10
KK # 200
kk # 5

Vous pouvez avec l'instruction "printf" formater la sortie. Ainsi si on reprend l'instruction "awk '//{print $1 $2}' test.txt" en ajoutant un format de sortie on obtient :

$ awk '//{printf "%-10s %s\n",$2, $3 }' test.txt

qui donne :

10         ddd
200        ee
5          fff

Sélection sur une des valeurs

Soit le fichier de test suivnat :

10 Ligne1 1

20 Ligne2 2

30 Ligne3 3

On souhaite sélectionner les lignes dont la première valeur est supérieure à 20. Solution :

$ awk '$1 > 20 { print ; }' test.txt

donne bien :

30 Ligne3 3

Les différents tests possibles sont :

  1. > pour strictement supérieur à
  2. < pour strictement inférieur à
  3. >= pour supérieur ou égal à
  4. <= pour inéfrieur ou égal à
  5. == pour égal à
  6. != pour différent de 
  7. ~ / valeur / égalité à une valeur alphanumérique
  8. !~ / valeur / inégalité à une valeur alphanumérique

Exemple pour les cas no 7 et 8 :

$ awk '$2 ~ /Ligne1/ { print ; }' test.txt 

donne bien : 

10 Ligne1 1

alors que 

$ awk '$2 !~ /Ligne1/ { print ; }' test.txt

donne 

10 Ligne2 2

20 Ligne3 3

Il est possible de combiner des conditions et donc des traitements différents en fonction des tests. Ainsi :

$ awk '$1 < 20 { print ; } $1 > 20 { print ; }' test.txt

donne :

10 Ligne1 1

 

30 Ligne3 3

On a donc retenu les lignes différentes de 20.

1. Awk reads the input files one line at a time.
2. For each line, it matches with given pattern in the given order, if matches performs the corresponding action.
3. If no pattern matches, no action will be performed.
4. In the above syntax, either search pattern or action are optional, But not both.
5. If the search pattern is not given, then Awk performs the given actions for each line of the input.
6. If the action is not given, print all that lines that matches with the given patterns which is the default action.
7. Empty braces with out any action does nothing. It wont perform default printing operation.
8. Each statement in Actions should be delimited by semicolon.

Exemple

Avec :
$cat employee.txt
100  Thomas  Manager    Sales       $5,000
200  Jason   Developer  Technology  $5,500
300  Sanjay  Sysadmin   Technology  $7,000
400  Nisha   Manager    Marketing   $9,500
500  Randy   DBA        Technology  $6,000

Default behavior of Awk
$ awk '{print;}' employee.txt
100  Thomas  Manager    Sales       $5,000
200  Jason   Developer  Technology  $5,500
300  Sanjay  Sysadmin   Technology  $7,000
400  Nisha   Manager    Marketing   $9,500
500  Randy   DBA        Technology  $6,000

Print the lines which matches with the pattern.
$ awk '/Thomas/
> /Nisha/' employee.txt
100  Thomas  Manager    Sales       $5,000
400  Nisha   Manager    Marketing   $9,500
Print only specific field

$ awk '{print $2,$5;}' employee.txt
Thomas $5,000
Jason $5,500
Sanjay $7,000
Nisha $9,500
Randy $6,000

$ awk '{print $2,$NF;}' employee.txt
Thomas $5,000
Jason $5,500
Sanjay $7,000
Nisha $9,500
Randy $6,000
Rapport
$ awk 'BEGIN {print "Name\tDesignation\tDepartment\tSalary";}
> {print $2,"\t",$3,"\t",$4,"\t",$NF;}
> END{print "Report Generated\n--------------";
> }' employee.txt
Name    Designation     Department      Salary
Thomas   Manager         Sales           $5,000
Jason    Developer       Technology      $5,500
Sanjay   Sysadmin        Technology      $7,000
Nisha    Manager         Marketing       $9,500
Randy    DBA             Technology      $6,000
Report Generated
--------------
Find the employees who has employee id greater than 200
$ awk '$1 >200' employee.txt
300  Sanjay  Sysadmin   Technology  $7,000
400  Nisha   Manager    Marketing   $9,500
500  Randy   DBA        Technology  $6,000
Print the list of employees in Technology department
$ awk '$4 ~/Technology/' employee.txt
200  Jason   Developer  Technology  $5,500
300  Sanjay  Sysadmin   Technology  $7,000
500  Randy   DBA        Technology  $6,000
Print number of employees in Technology department
$ awk 'BEGIN { count=0;}
$4 ~ /Technology/ { count++; }
END { print "Number of employees in Technology Dept =",count;}' employee.txt
Number of employees in Tehcnology Dept = 3

 

Fait le 03/06/2016

Tags: geek, awk