Guide approfondi de l'utilitaire awk sous Linux

Introduction à AWK

AWK est bien plus qu'une simple commande de filtrage ; c'est un langage de programmation interprété complet, spécialement conçu pour l'analyse et la transformation de données textuelles. Il permet de structurer, formater et extraire des informations à partir de fichiers texte ou de flux de données, en offrant des fonctionnalités avancées telles que les structures de contrôle, les tableaux associatifs et les expressions régulières.

Syntaxe fondamentale

La structure de base d'une commande AWK repose sur l'association d'un motif (patern) et d'une action :

awk [options] 'motif { action }' fichier(s)
awk [options] -f script.awk fichier(s)

L'action la plus courante est l'impression de données via print ou printf. Si aucun motif n'est spécifié, l'action s'applique à chaque ligne du fichier.

# Création d'un fichier de test
echo -e "serveurA 192.168.1.10 actif\nserveurB 192.168.1.11 inactif" > etat.txt

# Affichage de la ligne complète
awk '{print $0}' etat.txt

# Affichage de la première et de la troisième colonne
awk '{print $1, $3}' etat.txt

Par défaut, AWK découpe chaque ligne en champs (fields) en utilisant les espaces ou tabulations comme séparateurs. Le champ entier est représenté par $0, le premier par $1, et le dernier par $NF. La variable NF (sans le $) contient le nombre total de champs de la ligne courante.

Gestion des séparateurs

AWK distingue le séparateur de champs d'entrée (FS) et le séparateur de champs de sortie (OFS).

Séparateur d'entrée (FS)

Pour traiter des fichiers CSV ou utilisant des délimiteurs spécifiques, on modifie FS via l'option -F ou la variable intégrée :

# Fichier data.csv : id;nom;role
awk -F';' '{print $2, "est", $3}' data.csv

Séparateur de sortie (OFS)

Lors de l'impression de plusieurs champs séparés par des virgules, AWK insère la valeur de OFS (espace par défaut) entre eux.

awk -F';' -v OFS=' | ' '{print $1, $2, $3}' data.csv

Variables intégrées essentielles

AWK fournit de nombreuses variables prédéfinies pour faciliter le traitement :

  • NR : Numéro de la ligne courante (global).
  • FNR : Numéro de la ligne courante dans le fichier en cours de traitement (réinitialisé pour chaque nouveau fichier).
  • NF : Nombre de champs dans la ligne courante.
  • RS : Séparateur d'enregistrements d'entrée (par défaut, le saut de ligne).
  • ORS : Séparateur d'enregistrements de sortie.
  • FILENAME : Nom du fichier en cours de lecture.
# Afficher le numéro de ligne et le nombre de colonnes
awk '{print "Ligne", NR, ":", NF, "colonnes"}' etat.txt

Mise en forme avec printf

Contrairement à print qui ajoute automatiquement un saut de ligne, printf permet un contrôle précis du formatage, à l'instar du langage C.

awk -F';' '{printf "ID: %-5s | Nom: %-10s | Rôle: %s\n", $1, $2, $3}' data.csv

Notez que dans AWK, la chaîne de format et les arguments de printf doivent être séparés par une virgule, contrairement à la commande shell printf.

Les motifs (Patterns)

Les motifs agissent comme des filtres conditionnels. Seules les lignes correspondant au motif déclenchent l'exécution de l'action associée.

Motifs relationnels

Ils utilisent des opérateurs de comparaison (==, !=, <, >, <=, >=).

# Afficher les lignes ayant exactement 3 colonnes
awk 'NF == 3 {print $0}' etat.txt

# Filtrer selon la valeur d'un champ
awk '$3 == "actif" {print $1}' etat.txt

Motifs d'expressions régulières

Les regex doivent être placées entre barres obliques / /.

# Lignes commençant par "serveurA" ou "serveurB"
awk '/^serveur[AB]/ {print $0}' etat.txt

# Correspondance regex sur un champ spécifique
awk '$2 ~ /192\.168\.1\.[0-9]+/ {print $1}' etat.txt

Motifs de plage (Range)

Permetttent de cibler un bloc de lignes compris entre deux motifs.

# Traiter les lignes depuis "START" jusqu'à "END"
awk '/START/,/END/ {print $0}' journal.log

Blocs BEGIN et END

BEGIN s'exécute avant la lecture de la première ligne, et END après la dernière. Ils sont idéaux pour initialiser des variables ou afficher des résumés.

awk 'BEGIN {print "--- Début du rapport ---"} 
     {print $1, $2} 
     END {print "--- Fin du rapport ---"}' etat.txt

Structures de contrôle et actions

Les actions peuvent contenir des blocs de code complexes utilisant des instructions conditionnelles et des boucles.

Conditions if/else

awk '{
    if ($3 == "actif") {
        status = "OK"
    } else {
        status = "CRITIQUE"
    }
    print $1, status
}' etat.txt

Boucles for et while

# Boucle for classique
awk 'BEGIN {for (i = 1; i <= 3; i++) print "Itération", i}'

# Boucle while
awk 'BEGIN {i = 1; while (i <= 3) {print i; i++}}'

Instructions de flux : next et exit

  • next : Interrompt le traitement de la ligne courante et passe immédiatement à la suivante.
  • exit : Arrête la lecture des lignes d'entrée et saute directement au bloc END (s'il existe).

Tableaux associatifs

Les tableaux dans AWK sont toujours associatifs (indexés par des chaînes de caractères). Il n'est pas nécessaire de les déclarer ; ils sont créés dynamiquement lors de l'assignation.

awk 'BEGIN {
    config["timeout"] = 30
    config["retries"] = 3
    config["host"] = "localhost"
    
    # Vérifier l'existence d'une clé
    if ("timeout" in config) {
        print "Timeout défini sur :", config["timeout"]
    }
    
    # Parcourir le tableau
    for (key in config) {
        print key, "=", config[key]
    }
    
    # Supprimer un élément
    delete config["retries"]
}'

Comptage de fréquences

L'incrémentation d'un élément de tableau non initialisé le crée avec la valeur 0, ce qui est parfait pour les statistiques.

# Compter les occurrences de chaque méthode HTTP dans un log
awk '{methods[$1]++} END {for (m in methods) print m, methods[m]}' acces.log

Fonctions intégrées utiles

Fonctions mathématiques

  • int(x) : Tronque à l'entier inférieur.
  • rand() : Génère un nombre pseudo-aléatoire entre 0 et 1.
  • srand() : Initialise le générateur de nombres aléatoires.

Fonctions de manipulation de chaînes

  • length(s) : Retourne la longueur de la chaîne.
  • index(s, t) : Retourne la position de la sous-chaîne t dans s.
  • sub(r, s, t) : Remplace la première occurence de l'expression régulière r par s dans t.
  • gsub(r, s, t) : Remplace toutes les occurrences (global).
  • split(s, a, r) : Découpe la chaîne s selon le séparateur r et stocke le résultat dans le tableau a.
# Remplacer tous les espaces par des tirets dans le premier champ
awk '{gsub(/ /, "-", $1); print $1}' document.txt

Tri de tableaux (GNU AWK)

Les fonctions asort() et asorti() permettent de trier les valeurs ou les clés d'un tableau.

awk 'BEGIN {
    data["b"] = 20
    data["a"] = 10
    data["c"] = 30
    
    # Tri par clés (index)
    n = asorti(data, sorted_keys)
    for (i = 1; i <= n; i++) {
        print sorted_keys[i], "->", data[sorted_keys[i]]
    }
}'

Techniques avancées

Opérateur ternaire

L'opérateur ternaire condition ? valeur_si_vrai : valeur_si_faux permet de condenser les instructions if/else simples.

# Classifier les ports
awk '{port_type = ($1 < 1024) ? "Privilégié" : "Standard"; print $1, port_type}' ports.txt

Filtrage des lignes paires et impaires

Il est très simple d'extraire des lignes spécifiques en utilisant l'opérateur modulo sur la variable NR.

# Afficher uniquement les lignes impaires
awk 'NR % 2 != 0' fichier.txt

# Afficher uniquement les lignes paires
awk 'NR % 2 == 0' fichier.txt

Cette approche est préférable à l'utilisation de variables d'état basculantes, car elle est plus lisible, idiomatique et mathématiquement directe pour le traitement de flux.

Étiquettes: Linux awk shell-scripting text-processing regex

Publié le 6 juin à 00h31