awk, la commande de traitement de fichiers
Description
awk est un programme de traitement de fichiers "texte" qui est né en 1977, et est apparu dans UNIX v7. Son nom est constitué des initiales des noms de ces concepteurs :
-
Aho (Alfred V.),
-
Weinberger (Peter J.)
-
Kernighan (Brian W.).
Il est né de l’attrait qu’avaient ses concepteurs pour les expressions régulières. Suite au succès qu’il a rencontré auprès de ses utilisateurs, il a été enrichi et la première version a été remplacée par une version plus complète en 1985.
Il possède des mécanismes de traitement efficaces et implémente un langage de programmation rudimentaire. Bien qu’il n’ait pas été conçu pour cela, il a été néanmoins utilisé par Henry Spencer, le développeur de la version libre des fonctions regcomp() et regexec(), pour produire un assembleur pour les processeurs de la famille 6800 de Motorola, ce qui montre qu’on peut aussi l’utiliser pour des tâches relativement compliquées.
Son principe de traitement simple et très puissant fait de lui un outil efficace et agréable à utiliser, que l’on privilégie généralement pour les petits traitements.
Principe de fonctionnement
1. Principe général
Son principe de fonctionnement est simple : awk va lire toutes les lignes de l’entrée standard ou des fichiers dont les noms sont passés en arguments, et appliquer à chacune un ensemble de directives constituées de deux éléments :
-
le premier est une condition de traitement, permettant de déterminer s’il faut appliquer le traitement qui suit à la ligne courante,
-
le second décrit le traitement à effectuer si la condition qui précède est satisfaite.
Cet ensemble de directives est appelé programme AWK. Il peut être passé à awk en argument de ligne de commande, ou dans un fichier dont on lui passe le nom en argument. S’il est passé en argument de ligne de commande, il est important de bien maîtriser la syntaxe du shell pour ne pas faire d’erreur dans l’écriture du programme. Si le programme est long et compliqué, il sera moins risqué de le placer dans un fichier spécifique : on évitera ainsi des confusions possibles entre les métacaractères du shell et ceux de awk, et entre les variables positionnelles du shell et celles des champs de awk. Cette solution n’est toutefois pas envisageable si l’on doit passer une variable shell au programme awk.
La syntaxe est la suivante :
Syntaxe
awk [options] programme_awk [fichier ...]
où programme_awk est constitué d’une liste de directives au format suivant :
expression_de_sélection { traitement }
L’unité de données traitée par awk est la ligne. Chaque ligne est découpée en champs, référençables par les identifiants $1, $2, $3, ... , $n, où n est le numéro du dernier champ. La ligne complète est référençable par l’identifiant $0. Le séparateur de champs est par défaut un blanc (ensemble d’espaces ou de tabulations).
Cette possibilité de référencer les champs permet d’écrire des conditions de sélection très simplement, en exprimant une condition où figure le nom d’un ou plusieurs champs.
2. Expression de sélection
L’expression de sélection est une condition qui peut...
Les expressions régulières
1. Utilisation
Les expressions régulières de awk peuvent être utilisées indifféremment :
1. dans l’élément de sélection de la directive,
2. dans l’élément de traitement de la directive.
Lorsqu’elles sont utilisées dans l’élément de sélection, elles permettent de sélectionner les lignes sur lesquelles va être effectué le traitement.
Dans la directive de traitement, elles peuvent être utilisées dans des tests (comparaisons) ou dans les fonctions de traitement de chaînes.
Si elles doivent être utilisées plusieurs fois, ou si elles proviennent d’une source extérieure au programme awk, il est possible de les stocker dans une variable, puis d’utiliser cette variable.
2. Recherche de correspondance
a. Recherche avec /.../
Le résultat d’une recherche utilisant les slashes sera VRAI si la ligne courante de données contient une sous-chaîne de caractères correspondant à l’expression régulière placée entre les slashes. Si un bloc de traitement est associé à la recherche, il sera exécuté. Dans le cas contraire, c’est l’action par défaut qui sera exécutée, et la ligne entière sera affichée.
Syntaxe
/expr_reg/
Exemple
/[0-9]/
Cette directive permet la sélection de toutes les lignes de données contenant un chiffre décimal ([0-9]).
b. Recherche avec ~
Le résultat d’une recherche utilisant l’opérateur ~ sera VRAI si la ligne courante de données...
Fonctions de manipulation de chaînes
Les fonctions de manipulation de chaînes de caractères fournies par awk que nous détaillerons sont les suivantes :
-
length()
-
sub()
-
gsub()
-
match()
1. Fonction length()
La fonction length() permet d’obtenir la longueur d’une chaîne de caractères passée en paramètre. Si elle est appelée sans paramètre, elle retourne la longueur de l’enregistrement courant ($0).
Syntaxe
length
length(variable)
Exemple
lg = length(str);
l2 = length($2);
len = length;
2. Fonction sub()
La fonction sub() permet le remplacement de la première chaîne correspondant à l’expression régulière expr par la chaîne de caractères chaîne dans la variable spécifiée en troisième paramètre. Si le troisième paramètre est absent, la variable utilisée est l’enregistrement courant ($0).
Syntaxe
sub(expr, chaîne)
sub(expr, chaîne, variable)
Exemple
sub(/^[]*/, "", str);
3. Fonction gsub()
La fonction gsub() permet le remplacement de toutes les chaînes correspondant à...
Exercices
1. Exercice 1
Que fait le programme awk suivant, nommé exemple_select?
#!/bin/bash
cat <<- EOF | awk 'function disp(expr) {
if (NR != last_NR) {
if (last_NR != 0) {
printf("\n");
}
printf("%2d. %s\n", NR, $0);
}
printf("\tSelectionnee par : %s\n", expr);
last_NR = NR;
}
BEGIN {
last_NR = 0;
# Variables contenant les expressions regulieres
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
alpha_min = "[a-z]+";
alpha_maj = "[A-Z]+";
alpha = "[a-zA-z]+";
num = "[0-9]+";
alpha_num = "[a-zA-Z0-9]+";
# Premiere expression reguliere de recherche
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var = alpha_min;
}
/[a-z]+/ {
disp("/[a-z]+/");
}
$1 ~ /[a-z]+/ {
disp("$1 ~ /[a-z]+/");
}
$1 ~ "abcd" {
disp("$1 ~ \"abcd\"");
}
$1 ~ var {
disp("$1 ~ var , avec var = \"" var "\"");
}
/change/ {
if (var == alpha_min) {
var = alpha_maj;
}
else if (var == alpha_maj) {
var = num;
}
else if (var == num) {
var...