Fonctions intégrées

Etiquettes: 

Les fonctions sur les chaines de caractères

Les chaines de caractères

En plus de fonctions de base, awk dispose également de fonctions dédiées aux traitements des chaines de caractères, facilitant ce genre d'opérations. La liste de ces fonctions est la suivante :

Fonction de string Description
gsub(exp,sub,str) Substitue globalement par la chaine sub chaque expression régulière exp trouvée dans la chaine str et retourne le nombre de substitutions. Si str n'est pas indiquée, par défaut $0 est utilisé.
index(str,st)

Retourne la position du string st dans la chaine str, ou 0 si non trouvé.

length(str) Retourne la longueur de la chaine str. Si str n'est pas indiquée, par défaut $0 est utilisé.
match(str,exp) Retourne la position de l'expression régulière exp dans la chaine str, ou 0 si non trouvé. Affecte les valeurs aux variables RSTART et RLENGTH.
split(str,tab,sep) Sépare la chaine str en éléments dans un tableau tab et en utilisant le séparateur sep. Si sep n'est pas renseigné, FS est utilisé par défaut.
sprintf("format",exp) Retourne une chaine au lieu de l'affichage vers la sortie standard, contrairement à printf().
sub(exp,sub,str) Comme gsub(), mais ne substitue par sub que la première expression exp trouvée dans str.
substr(str,pos,long) Retourne une partie du string str commançant à la position pos et de longueur long. Si long n'est pas indiqué, substr() utilise tout le reste de str.
tolower(str) Met en minuscules toute la chaine str et retourne la nouvelle chaine.
toupper(str) Met en majuscules toute la chaine str et retourne la nouvelle chaine.

Exemple :

gsub : remplacer par un @ toutes les lettres a et A du fichier depts2012.txt

$ head depts2012.txt | awk '{gsub(/a|A/,"@") ; print}'
REGION  DEP     CHEFLIEU        TNCC    NCC     NCCENR
82      01      01053   5       @IN     @in
22      02      02408   5       @ISNE   @isne
83      03      03190   5       @LLIER  @llier
93      04      04070   4       @LPES-DE-H@UTE-PROVENCE @lpes-de-H@ute-Provence
93      05      05061   4       H@UTES-@LPES    H@utes-@lpes
93      06      06088   4       @LPES-M@RITIMES @lpes-M@ritimes
82      07      07186   5       @RDECHE @rdèche
21      08      08105   4       @RDENNES        @rdennes
73      09      09122   5       @RIEGE  @riège
$

index : connaitre la position d'un caractère dans une chaine

$ head depts2012.txt | awk '{pos=index($5,"-") ; print "Position du tiret : " , pos , "\tdans la chaine : " , $5}'
Position du tiret :  0  dans la chaine :  NCC
Position du tiret :  0  dans la chaine :  AIN
Position du tiret :  0  dans la chaine :  AISNE
Position du tiret :  0  dans la chaine :  ALLIER
Position du tiret :  6  dans la chaine :  ALPES-DE-HAUTE-PROVENCE
Position du tiret :  7  dans la chaine :  HAUTES-ALPES
Position du tiret :  6  dans la chaine :  ALPES-MARITIMES
Position du tiret :  0  dans la chaine :  ARDECHE
Position du tiret :  0  dans la chaine :  ARDENNES
Position du tiret :  0  dans la chaine :  ARIEGE
$

length : connaitre le nombre de caractères dans une chaine

$ tail depts2012.txt | awk '{lg=length($5) ; printf ("Il y a %3d caracteres dans la chaine %30s\n" , lg , $5)}'
Il y a   7 caracteres dans la chaine                        ESSONNE
Il y a  14 caracteres dans la chaine                 HAUTS-DE-SEINE
Il y a  17 caracteres dans la chaine              SEINE-SAINT-DENIS
Il y a  12 caracteres dans la chaine                   VAL-DE-MARNE
Il y a  10 caracteres dans la chaine                     VAL-D'OISE
Il y a  10 caracteres dans la chaine                     GUADELOUPE
Il y a  10 caracteres dans la chaine                     MARTINIQUE
Il y a   6 caracteres dans la chaine                         GUYANE
Il y a  10 caracteres dans la chaine                     LA_REUNION
Il y a   7 caracteres dans la chaine                        MAYOTTE
$

match : connaitre la position d'une expression dans une chaine

$ tail depts2012.txt | awk '{pos=match($5,/-DE-/) ; printf("Position de l expression recherchee \"-DE-\" : %2d dans la chaine %20s\tRSTART = %2d\tRLENGTH = %2d\n" , pos , $5 , RSTART , RLENGTH)}'
Position de l expression recherchee "-DE-" :  0 dans la chaine              ESSONNE     RSTART =  0     RLENGTH = -1
Position de l expression recherchee "-DE-" :  6 dans la chaine       HAUTS-DE-SEINE     RSTART =  6     RLENGTH =  4
Position de l expression recherchee "-DE-" :  0 dans la chaine    SEINE-SAINT-DENIS     RSTART =  0     RLENGTH = -1
Position de l expression recherchee "-DE-" :  4 dans la chaine         VAL-DE-MARNE     RSTART =  4     RLENGTH =  4
Position de l expression recherchee "-DE-" :  0 dans la chaine           VAL-D'OISE     RSTART =  0     RLENGTH = -1
Position de l expression recherchee "-DE-" :  0 dans la chaine           GUADELOUPE     RSTART =  0     RLENGTH = -1
Position de l expression recherchee "-DE-" :  0 dans la chaine           MARTINIQUE     RSTART =  0     RLENGTH = -1
Position de l expression recherchee "-DE-" :  0 dans la chaine               GUYANE     RSTART =  0     RLENGTH = -1
Position de l expression recherchee "-DE-" :  0 dans la chaine           LA_REUNION     RSTART =  0     RLENGTH = -1
Position de l expression recherchee "-DE-" :  0 dans la chaine              MAYOTTE     RSTART =  0     RLENGTH = -1
$

split : séparer une chaine en éléments dans un tableau

$ tail depts2012.txt | awk '/-/{split($5,tab,"-") ; printf("tab1 = %10s\ttab2 = %10s\ttab3 = %10s\n" , tab[1] , tab[2] , tab[3])}'
tab1 =      HAUTS       tab2 =         DE       tab3 =      SEINE
tab1 =      SEINE       tab2 =      SAINT       tab3 =      DENIS
tab1 =        VAL       tab2 =         DE       tab3 =      MARNE
tab1 =        VAL       tab2 =     D'OISE       tab3 =
$

sprintf (contrairement à la commande printf, avec sprintf le retour chariot \n n'est pas obligatoire)

$ tail depts2012.txt | awk '/-/{split($5,tab,"-") ; chaine=sprintf("tab1 = %10s\ttab2 = %10s\ttab3 = %10s" , tab[1] , tab[2] , tab[3]) ; print chaine}'
tab1 =      HAUTS       tab2 =         DE       tab3 =      SEINE
tab1 =      SEINE       tab2 =      SAINT       tab3 =      DENIS
tab1 =        VAL       tab2 =         DE       tab3 =      MARNE
tab1 =        VAL       tab2 =     D'OISE       tab3 =
$

sub : remplacer par un @ la première lettre a ou A de chaque ligne du fichier depts2012.txt

$ head depts2012.txt | awk '{sub(/a|A/,"@") ; print}'
REGION  DEP     CHEFLIEU        TNCC    NCC     NCCENR
82      01      01053   5       @IN     Ain
22      02      02408   5       @ISNE   Aisne
83      03      03190   5       @LLIER  Allier
93      04      04070   4       @LPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93      05      05061   4       H@UTES-ALPES    Hautes-Alpes
93      06      06088   4       @LPES-MARITIMES Alpes-Maritimes
82      07      07186   5       @RDECHE Ardèche
21      08      08105   4       @RDENNES        Ardennes
73      09      09122   5       @RIEGE  Ariège
$

substr : extraire une partie d'une chaine

$ tail depts2012.txt | awk '{chaine=substr($5,1,3) ; printf("Les 3 premieres lettres de %20s sont : %3s\n" , $5 , chaine)}'
Les 3 premieres lettres de              ESSONNE sont : ESS
Les 3 premieres lettres de       HAUTS-DE-SEINE sont : HAU
Les 3 premieres lettres de    SEINE-SAINT-DENIS sont : SEI
Les 3 premieres lettres de         VAL-DE-MARNE sont : VAL
Les 3 premieres lettres de           VAL-D'OISE sont : VAL
Les 3 premieres lettres de           GUADELOUPE sont : GUA
Les 3 premieres lettres de           MARTINIQUE sont : MAR
Les 3 premieres lettres de               GUYANE sont : GUY
Les 3 premieres lettres de           LA_REUNION sont : LA_
Les 3 premieres lettres de              MAYOTTE sont : MAY
$

tolower : convertir une chaine majuscule en minuscule

$ tail depts2012.txt | awk '{chaine=tolower($5) ; printf("%20s en minuscule : %20s\n" , $5 , chaine)}'
             ESSONNE en minuscule :              essonne
      HAUTS-DE-SEINE en minuscule :       hauts-de-seine
   SEINE-SAINT-DENIS en minuscule :    seine-saint-denis
        VAL-DE-MARNE en minuscule :         val-de-marne
          VAL-D'OISE en minuscule :           val-d'oise
          GUADELOUPE en minuscule :           guadeloupe
          MARTINIQUE en minuscule :           martinique
              GUYANE en minuscule :               guyane
          LA_REUNION en minuscule :           la_reunion
             MAYOTTE en minuscule :              mayotte
$

toupper : convertir une chaine minuscule en majuscule

$ tail depts2012.txt | awk '{chaine=toupper($6) ; printf("%20s en MAJUSCULE : %20s\n" , $6 , chaine)}'
             Essonne en MAJUSCULE :              ESSONNE
      Hauts-de-Seine en MAJUSCULE :       HAUTS-DE-SEINE
   Seine-Saint-Denis en MAJUSCULE :    SEINE-SAINT-DENIS
        Val-de-Marne en MAJUSCULE :         VAL-DE-MARNE
          Val-d'Oise en MAJUSCULE :           VAL-D'OISE
          Guadeloupe en MAJUSCULE :           GUADELOUPE
          Martinique en MAJUSCULE :           MARTINIQUE
              Guyane en MAJUSCULE :               GUYANE
             Mayotte en MAJUSCULE :              MAYOTTE
$

Etiquettes: 

Les fonctions mathématiques

Les fonctions mathématiques

awk dispose également de fonctions dédiées aux traitements numériques. Celles-ci sont les suivantes :

Fonction mathématique Description
cos(r) Cosinus de l'angle r (r en radians)
exp(x) Exponentiel de x
int(x) Valeur entière de x
log(x) Logarithme de x
sin(r) Sinus de l'angle r (r en radians)
sqrt(x) Racine carrée de x
atan2(y,x) Arc tangente de y/x
rand() Nombre pseudo-aléatoire compris entre 0 et 1
srand(n) Réinitialise la fonction rand()

Exemple :

cos

$ echo 50 | awk '{print cos($1)}'
0.964966
$

exp

$ echo 5 | awk '{print exp($1)}'
148.413
$

int

$ echo 5.4 | awk '{print $1 , " ==> " , int($1)}'
5.4  ==>  5
$

log

$ echo 5 | awk '{print log($1)}'
1.60944
$

sin

$ echo 50 | awk '{print sin($1)}'
-0.262375
$

sqrt

$ echo 81 | awk '{print sqrt($1)}'
9
$

atan2

$ echo 50 25 | awk '{print atan2($1,$2)}'
1.10715
$

rand

$ echo | awk '{print rand()}'
0.795735
$ echo | awk '{print rand()}'
0.321886
$ echo | awk '{print int(rand()*1000)}'
792
$

Etiquettes: 

Autres fonctions

Etiquettes: 

La fonction getline

La fonction getline permet de lire la ligne suivante du flux sans remonter au début du traitement (contrairement à next) et de lire une ligne à partir d'un fichier, de l'entrée standard ou d'un tube.

Valeur de retour :
- 1 en cas de succès
- 0 en fin de fichier
- -1 en cas d'erreur

Il ne faut pas mettre de parenthèse lors de l'appel de la fonction getline.

Syntaxe

getline [variable]
Lecture de la ligne suivante du flux.
getline [variable] < "fichier"
Lecture d'une ligne à partir d'un fichier
"commande" | getline [variable]
Lecture d'une ligne provenant du résultat d'une commande du système.

La ligne lue par getline est stockée dans la variable variable ou $0 si aucun nom de variable n'est spécifié. Le nom de fichier "-" représente l'entrée standard.

Premier exemple :

Reconstituer des phrases écrites sur plusieurs lignes et délimitées par un caractère spécifique.

Le fichier suivant contient des phrases scindées en plusieurs lignes. Le scindement est caractérisé par un anti-slash en fin de ligne.

$ cat text.txt
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
Maecenas porttitor congue massa. \
Fusce posuere, magna sed pulvinar ultricies,purus lectus malesuada libero, \
sit amet commodo magna eros quis urna.
Nunc viverra imperdiet enim. \
Fusce est. \
Vivamus a tellus.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. \
Proin pharetra nonummy pede. Mauris et orci.
Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.
Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. \
Mauris eget neque at sem venenatis eleifend. \
Ut nonummy.
$.

Le script suivant va analyser chaque ligne du fichier et reconstituer l'intégralité des phrases grâce à la fonction getline.

$ nl script10.awk
     1  {
     2          ligne=$0
     3          # Tant que la ligne se termine par \
     4          while(ligne ~ /\\$/){
     5                  # Suppression de \
     6                  sub(/\\$/,"",ligne)
     7                  # Lecture de la ligne suivante
     8                  getline nextline
     9                  # Concatenation de ligne et nextline
    10                  ligne=ligne nextline
    11          }
    12          # Affichage de la ligne globale
    13          printf("------- Contenu de la phrase %d -------\n%s\n",++num,ligne)
    14  }
$

Exécution du script

$ awk -f script10.awk text.txt
------- Contenu de la phrase 1 -------
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies,purus lectus malesuada libero, sit amet commodo magna eros quis urna.
------- Contenu de la phrase 2 -------
Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.
------- Contenu de la phrase 3 -------
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.
------- Contenu de la phrase 4 -------
Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.
------- Contenu de la phrase 5 -------
Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.
$

Deuxième exemple :

Lire une entrée clavier et le contenu d'un fichier extérieur au flux courant.

Rechercher le nom d'un département dans le fichier depts2012.txt en saisissant son nom au clavier.

$ cat depts2012.txt
REGION  DEP     CHEFLIEU        TNCC    NCC     NCCENR
82      01      01053   5       AIN     Ain
22      02      02408   5       AISNE   Aisne
83      03      03190   5       ALLIER  Allier
93      04      04070   4       ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93      05      05061   4       HAUTES-ALPES    Hautes-Alpes
...
01      971     97105   3       GUADELOUPE      Guadeloupe
02      972     97209   3       MARTINIQUE      Martinique
03      973     97302   3       GUYANE  Guyane
04      974     97411   0       LA_REUNION      La Réunion
06      976     97608   0       MAYOTTE Mayotte
$

Le script suivant demande une saisie au clavier et recherche dans le fichier précédent le nom saisi.

$ nl script11.awk
     1  BEGIN{
     2          # Boucle infinie
     3          while(1){
     4                  printf("Rechercher le nom (ctrl+d pour quitter): ")
     5                  # Lecture clavier sur l'entree standard "-"
     6                  # Arret du programme si le code retour de getline est different de 1
     7                  if((getline nom < "-") != 1) break
     8                  # Si aucun nom saisi, on recommence
     9                  if(length(nom)==0) continue
    10                  trouve="false"
    11                  # Boucle de lecture du fichier depts2012.txt
    12                  # Tant que le code retour de getline est egal a 1
    13                  while((getline < "depts2012.txt")==1){
    14                          # Comparaison faite sans tenir compte de la casse
    15                          if(tolower($5)==tolower(nom)){
    16                                  trouve="true"
    17                                  # Affichage du resultat trouve
    18                                  print $0
    19                                  # On sort de la boucle while
    20                                  break
    21                          }
    22                  }
    23                  # Fermeture du fichier
    24                  close("depts2012.txt")
    25                  # Affichage du message si le nom n'a pas ete trouve
    26                  if(trouve=="false") print nom , "n'est pas dans le fichier"
    27          }
    28          # Affichage du message avant l'arret du programme
    29          print "\nA bientot"
    30  }
$

Exécution du script

$ awk -f script11.awk
Rechercher le nom (ctrl+d pour quitter): ain
82      01      01053   5       AIN     Ain
Rechercher le nom (ctrl+d pour quitter): somme
22      80      80021   3       SOMME   Somme
Rechercher le nom (ctrl+d pour quitter):
Rechercher le nom (ctrl+d pour quitter): var
93      83      83137   2       VAR     Var
Rechercher le nom (ctrl+d pour quitter):
A bientot
$

Troisième exemple :

Utiliser getline pour lire le résulat d'une commande système.

$ nl script12.awk
     1  BEGIN{
     2          "date" | getline
     3          print "$0 = ",$0
     4          for(i=1;i<=NF;i++){
     5                  printf("$%d = %s\n",i,$i)
     6          }
     7  }
$ awk -f script12.awk
$0 =  Tue May 15 19:35:25 CEST 2012
$1 = Tue
$2 = May
$3 = 15
$4 = 19:35:25
$5 = CEST
$6 = 2012
$

Etiquettes: 

La fonction close

La fonction close permet de fermer un fichier ou un tube de communication. Si l'appel à cette fonction est omis, les ressources sont libérées à la terminaison du script.

L'ordre de fermeture est intéressant dans les cas suivants :
- pouvoir se repositionner en début de fichier au sein du même processus (fermeture puis réouverture)
- fermer un tube de communication pour s'en servir à nouveau
- libérer les ressources au fur et à mesure des besoins (le système limite les processus, en ce qui concerne le nombre de fichiers/tubes ouverts simultanément).

Syntaxe

close("fichier")
close("commande")

Il est indispensable de fermer un fichier pour pouvoir le relire à partir du début.

Exemple :

$ nl script13.awk
     1  BEGIN {
     2          fichier = "/root/fichier1.txt"
     3          i=1
     4          while(i<=10){
     5                  print rand() > fichier
     6                  i++
     7          }
     8          # Fermeture du fichier
     9          close(fichier)
    10          while((getline<fichier)==1){
    11                  print $0
    12          }
    13  }
$ awk -f script13.awk
0.692303
0.532958
0.423364
0.484409
0.455168
0.0133607
0.554077
0.375875
0.325945
0.164046
$

Etiquettes: 

La fonction system

La fonction system permet d'exécuter une commande du système.

Syntaxe

system("commande")

La fonction retourne le statut renvoyé par la commande.

Exemple :

$ awk 'BEGIN{system("uptime")}'
 21:06:15 up 5 days,  2:22,  0 users,  load average: 0.00, 0.00, 0.00
$

Idem mais en se servant d'une variable

$ awk 'BEGIN{fic="depts2012.txt";system("ls -l " fic)}'
-rw-r--r-- 1 root root 3504 May 10 14:05 depts2012.txt
$

Etiquettes: