# Awk

awk — dont le nom vient des trois créateurs, Alfred Aho, Peter Weinberger et Brian Kernighan — est un langage de traitement par lignes de fichiers plats, disponible sur la plupart des systèmes Unix et sous Windows avec MinGW, Cygwin ou Gawk. Il est principalement utilisé pour la manipulation de fichiers textuels pour des opérations de recherches, de remplacement et de transformations complexes.

## Présentation

Awk est le plus souvent utilisé pour la production de fichiers textes aux spécifications particulières (échanges entre différents systèmes d'informations hétérogènes). Il est aussi utilisé comme analyseur (parser) de fichiers XML ou de fichiers textes pour générer des commandes SQL à partir des données extraites. Il peut être utilisé enfin pour des opérations de calculs complexes et mise en forme de données brutes pour faire des tableaux statistiques.
On distingue awk, la commande originale, du new awk (nawk), arrivée un peu plus tard sur le marché. Les implémentations GNU de awk, sont en fait des new awk. On trouve en général la commande awk dans /usr/bin sous Unix, mais certains systèmes GNU/Linux la placent dans /bin. Cela impose un shebang du type #!/usr/bin/env awk -f pour assurer une portabilité maximale des scripts awk.
Il agit comme un filtre programmable prenant une série de lignes en entrée (sous forme de fichiers ou directement via l'entrée standard) et écrivant sur la sortie standard, qui peut être redirigée vers un autre fichier ou programme. Un programme Awk est composé de trois blocs distincts utilisables ou non pour le traitement d'un fichier (prétraitement, traitement, post-traitement). Awk lit l'entrée ligne par ligne, puis sélectionne (ou non) les lignes à traiter par des expressions rationnelles (et éventuellement des numéros de lignes). Une fois la ligne sélectionnée, elle est découpée en champs selon un séparateur d'entrée indiqué dans le programme awk par le symbole FS (qui par défaut correspond au caractère espace ou tabulation). Puis les différents champs sont disponibles dans des variables : $1 (premier champ), $2 (deuxième champ), $3 (troisième champ), …, $NF (dernier champ).
« awk » est aussi l'extension de nom de fichier utilisée pour les scripts écrits dans ce langage (rarement utilisée).
La syntaxe est inspirée du C : awk [options] [programme] [fichier] où la structure du programme est : 'motif1 { action1 } motif2 { action2 } …'
Chaque ligne du fichier est comparée successivement aux différents motifs (le plus souvent des expressions rationnelles, et globalement une expression booléenne) et l'action de chaque motif renvoyant la valeur vraie est exécutée dans l'ordre des motifs. Lorsque tous les motifs ont été évalués, le programme passe au traitement de la ligne suivante.
Quelques options :
* -F séparateur : permet de modifier le séparateur de champs ;
* -f fichier : lit le programme à partir d'un fichier.
* -v awkVar=$shellVar : Permet de facilement intégrer des variables du shell dans le code awk.

## Description technique

Un fichier est divisé en enregistrements (records en anglais) eux-mêmes divisés en champs (fields en anglais). Par défaut, les enregistrements sont des lignes et les champs sont des mots.
* Les enregistrements sont séparés les uns des autres par un caractère spécial jouant le rôle de séparateur. Par défaut, c'est le séparateur de lignes (par défaut "\n"), ainsi un enregistrement est une ligne. Le nombre de lignes lues à un instant donné est stocké dans un compteur dénommé NR.
* Chaque ligne est divisée en champs successifs, séparés par défaut par un espace ou une tabulation. Lors du traitement d'une ligne, le nombre de champ de cette ligne est contenu dans un compteur dénommé NF.
Les séparateurs d'entrée-sortie sont stockés dans des variables et peuvent être modifiés :
* pour les lignes, les variables sont respectivement RS et ORS,
* pour les champs, les variables sont respectivement FS et OFS
* $n désigne le ne champ, où n est un entier strictement positif,
* $0 désigne la ligne entière.
On dispose de deux motifs spéciaux :
* BEGIN : ce motif est vrai uniquement avant le traitement de la première ligne ;
* END : ce motif est vrai uniquement une fois qu'il ne reste plus de lignes à traiter.
Pour définir un intervalle, on utilise la virgule comme ceci :
* NR == 1, NR == 10 : l'action associée sera appliquée aux lignes 1 à 10.
Plusieurs fonctions sont déjà implémentées :
* print, printf : fonctions d'affichage ;
* cos(expr), sin(expr), exp(expr), log(expr) ;
* getline : lit l'entrée suivante d'une ligne, et retourne 0 s'il s'agit de la fin du fichier (EOF : end of file), 1 sinon ;
* index(s1, s2) : retourne la position de la chaîne de caractères s2 dans la chaîne s1, et retourne 0 si s2 ne figure pas dans s1 ;
* int(expr) : partie entière d'une expression ;
* length(s) : longueur de la chaîne s ;
* substr(s,n,l) : retourne la partie de la chaîne de caractères s commençant à la position n, et d'une longueur l.
On dispose de structures de contrôles. La syntaxe provient directement du C :
* if (test) {actions} else {actions}
* while (test) {actions}
* do {actions} while (test)
* for (expr1;expr2;expr3) {actions}
* continue : passe à l'élément suivant dans une boucle
* break : sort d'une boucle
* function nom(args) { actions} : définit une nouvelle fonction. La grammaire de awk ne prévoit pas de variables locales, et il est d'usage de les déclarer comme argument.
Par rapport au C, il y a quelques extensions :
* next : passe à la ligne suivante
* tableaux associatifs : tableau[texte]=valeur
* for (var in tableau) {actions}

## Quelques exemples

* awk '{print $0}' fichier : affiche toutes les lignes de fichier (idem que cat fichier).
* awk '/2/ {print $0}' fichier : affiche toutes les lignes où le caractère 2 est présent (idem que grep '2' ref.txt).
* awk '$1~/2/ {print $0}' fichier : affiche toutes les lignes où le caractère 2 est présent dans le premier champ.
* awk '{print NR ":", $0}' fichier : affiche le contenu de fichier, mais chaque ligne est précédée de son numéro.
* awk -F: '{print $1}' /etc/passwd : renvoie la liste des utilisateurs (idem cut -d : -f 1 /etc/passwd).
* awk 'BEGIN {FS = ":"}{print $1}' /etc/passwd : idem que la précédente commande
* awk '{s=s+$1} END {print s}' fichier : écrit la somme de tous les nombres de la première colonne de fichier.
* awk '/Motif1/ , /Motif2/' fichier : écrit toutes les lignes contenues dans le fichier entre le Motif1 et le Motif2.

## Implémentation

Il existe divers programmes qui utilisent la syntaxe du awk original, voici les plus connus :
* nawk (abréviation de new awk), qui étend les fonctionnalités de la version initiale ;
* mawk, une version connue pour sa rapidité dans certains cas ;
* gawk, la version du GNU disponible sous les principaux OS, avec une modification qui existe pour travailler sur le réseau TCP/IP ;
* jawk, une version fonctionnant sur la machine virtuelle Java.