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
$
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
$
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
$
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
$
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
$