DevOps Bootcamp · Leçon

Fonctions awk, mise en forme avec printf et génération de rapports

Définissez des fonctions utilisateur et utilisez printf pour produire des rapports tabulaires soignés à partir de flux de données brutes.

Leçon 4 sur 413 étapes

Fonctions awk, mise en forme avec printf et génération de rapports est une leçon DevOps Bootcamp gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage DevOps Bootcamp, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours DevOps Bootcamp comprend 4 leçons au total.

Pourquoi les fonctions et printf sont importants dans awk

À mesure que vos programmes awk passent de commandes d’une ligne à des chaînes de traitement en plusieurs étapes, deux fonctionnalités deviennent essentielles : les fonctions définies par l’utilisateur et la mise en forme avec printf.

Les fonctions vous permettent d’encapsuler une logique réutilisable — calculer un pourcentage, supprimer les espaces superflus d’une chaîne, convertir une unité — afin de l’écrire une seule fois et de l’appeler n’importe où dans le même programme. printf vous permet de contrôler exactement l’apparence de la sortie : largeur des colonnes, nombre de décimales, remplissage et alignement.

Ensemble, ces fonctionnalités transforment des lignes de journaux brutes en rapports soignés et lisibles sur lesquels les ingénieurs et les responsables peuvent agir.

  • Les fonctions réduisent la duplication et rendent les programmes testables séparément.
  • printf aligne les données dans des colonnes de largeur fixe afin que les rapports restent lisibles même lorsque la longueur des entrées varie.
  • Ces deux fonctionnalités fonctionnent avec POSIX awk, gawk et mawk — aucune extension n’est nécessaire.

Définir une fonction utilisateur dans awk

Une fonction utilisateur se déclare avec le mot-clé function, avant ou après les règles de motif-action. La syntaxe est la suivante :

function name(param1, param2,    local1, local2) {
    # body
    return value
}

Un idiome important d’awk : les variables locales sont simplement des paramètres supplémentaires précédés de davantage d’espaces. Il n’existe pas de mot-clé local — la convention des espaces supplémentaires indique que ces paramètres sont locaux et non des arguments transmis par l’appelant.

  • Toutes les variables qui ne sont pas déclarées comme paramètres sont globales par défaut.
  • Les fonctions peuvent s’appeler elles-mêmes de manière récursive.
  • return est facultatif ; sans lui, la fonction renvoie une chaîne vide.
#!/usr/bin/env bash
# Demonstrate a simple awk user function
echo '10 3
7 0
100 4' | awk '
function divide(a, b,    result) {
    if (b == 0) return "ERR"
    result = a / b
    return result
}
{
    print $1 "/" $2 " = " divide($1, $2)
}
'

Fonctions et logique de traitement des chaînes

Les fonctions sont particulièrement utiles pour les opérations répétées sur les chaînes. Prenons la suppression des espaces en début et en fin — une opération souvent nécessaire sur les données brutes de journaux avant une comparaison ou un rapport.

L’exemple ci-dessous définit trim(s) avec gsub et l’utilise pour chaque enregistrement, ce qui garde la règle principale claire et lisible.

  • gsub(regex, replacement, target) modifie target directement et renvoie le nombre de substitutions.
  • Placer la logique d’expression régulière dans une fonction permet au bloc de règle de rester centré sur la logique métier.
  • Vous pouvez effectuer un test unitaire en transmettant directement des chaînes conçues à la main dans un bloc BEGIN.
#!/usr/bin/env bash
# trim() strips leading/trailing spaces; used to normalise CSV-like data
printf '  alice , 90 \n bob , 85 \n  carol , 92 \n' | awk -F',' '
function trim(s) {
    gsub(/^[ \t]+|[ \t]+$/, "", s)
    return s
}
{
    name  = trim($1)
    score = trim($2)
    print name, score
}
'

Introduction à printf dans awk

Dans awk, printf suit les mêmes conventions que le langage C et que le printf intégré de Bash. La différence principale avec print est que printf n’ajoute jamais automatiquement de saut de ligne — vous devez ajouter vous-même \n.

Spécificateurs de format courants :

  • %s — chaîne
  • %d — entier
  • %f — nombre à virgule flottante
  • %e — notation scientifique
  • %g — le plus court entre %f et %e

La largeur et la précision sont contrôlées en plaçant des nombres entre % et le spécificateur : %-20s aligne à gauche dans un champ de 20 caractères ; %8.2f donne un nombre flottant sur 8 caractères avec 2 décimales.

#!/usr/bin/env bash
# printf format specifiers in awk
echo '' | awk '
BEGIN {
    printf "%s\n",        "plain string"
    printf "%10s\n",     "right-pad"
    printf "%-10s|\n",   "left-pad"
    printf "%8.2f\n",    3.14159
    printf "%08d\n",     42
    printf "%e\n",       123456.789
}
'

Créer l’en-tête d’un rapport avec printf

Un rapport soigné nécessite une ligne d’en-tête et une ligne de séparation. Le bloc BEGIN est l’endroit naturel pour les produire : il s’exécute une fois avant le traitement de toute entrée.

L’astuce consiste à faire correspondre exactement les largeurs de l’en-tête à celles utilisées dans les lignes de données. Définir des constantes de largeur dans BEGIN (ou dans une fonction) permet de garder l’ensemble cohérent lorsque vous modifiez ensuite la largeur des colonnes.

  • Utilisez printf avec une chaîne de tirets pour tracer la ligne de séparation.
  • Terminez toujours les lignes d’en-tête par \n.
  • Combinez un en-tête BEGIN, des lignes par enregistrement et un pied de page END pour obtenir une structure de rapport complète.
#!/usr/bin/env bash
# Print a report header in BEGIN, data rows per-record, total in END
printf 'alice 9200 12\nbob 8750 10\ncarol 10400 14\n' | awk '
BEGIN {
    printf "%-10s %10s %6s %12s\n", "Name", "Salary", "Months", "Annual"
    printf "%s\n", "----------------------------------------------"
    total = 0
}
{
    annual = $2 * $3
    total += annual
    printf "%-10s %10d %6d %12d\n", $1, $2, $3, annual
}
END {
    printf "%s\n", "----------------------------------------------"
    printf "%-10s %10s %6s %12d\n", "TOTAL", "", "", total
}
'

Fonctions utilisateur pour la logique de mise en forme

Lorsque vous créez des rapports à plusieurs colonnes, vous devez souvent effectuer le même appel de mise en forme à plusieurs endroits — par exemple pour afficher une barre de pourcentage ou convertir des octets en unité lisible. Placer cette logique dans une fonction évite la duplication et facilite la modification globale du format.

La fonction ci-dessous convertit les octets en KB, MB ou GB et renvoie une chaîne mise en forme. La règle appelante transmet simplement $NF (le dernier champ) et affiche la valeur renvoyée.

#!/usr/bin/env bash
# human_bytes() converts raw byte counts to KB/MB/GB strings
printf 'var.log 1024\naccess.log 2097152\ncore.dump 1073741824\ntiny.txt 512\n' | awk '
function human_bytes(n,    s) {
    if (n >= 1073741824) { s = sprintf("%.1f GB", n/1073741824) }
    else if (n >= 1048576) { s = sprintf("%.1f MB", n/1048576) }
    else if (n >= 1024)    { s = sprintf("%.1f KB", n/1024) }
    else                   { s = sprintf("%d B",    n) }
    return s
}
BEGIN { printf "%-20s %10s\n", "File", "Size"; print "------------------------------" }
{ printf "%-20s %10s\n", $1, human_bytes($2) }
'

Accumuler des données dans des tableaux avant l’affichage

Les rapports réels nécessitent souvent des totaux, des moyennes ou des classements — des valeurs que vous ne pouvez calculer qu’après avoir parcouru toutes les données d’entrée. Le modèle est le suivant :

  • Accumuler les données dans des tableaux associatifs pendant la phase de traitement de chaque enregistrement.
  • Calculer les valeurs dérivées (moyennes, pourcentages) dans END.
  • Produire la sortie mise en forme uniquement depuis END, afin que les largeurs puissent s’adapter à l’ensemble des données.

Ce modèle de sortie différée est l’un des idiomes les plus puissants pour générer des rapports avec awk. L’exemple ci-dessous comptabilise le nombre de requêtes et le nombre d’octets de réponse pour chaque code d’état HTTP à partir d’un journal d’accès.

#!/usr/bin/env bash
# Summarise an nginx-style access log by HTTP status code
printf '127.0.0.1 200 1234\n127.0.0.1 404 512\n10.0.0.2 200 8900\n10.0.0.3 500 256\n10.0.0.4 200 4096\n10.0.0.5 404 300\n' | awk '
{
    status  = $2
    bytes   = $3
    count[status]++
    total_bytes[status] += bytes
}
END {
    printf "%-8s %8s %14s\n", "Status", "Requests", "Total Bytes"
    print  "-----------------------------------"
    for (s in count)
        printf "%-8s %8d %14d\n", s, count[s], total_bytes[s]
}
'

Fonctions récursives dans awk

awk prend en charge la récursivité. Elle est couramment utilisée pour calculer des factorielles ou générer des chaînes répétitives (par exemple une ligne de tirets dont la longueur correspond à la largeur du terminal). La récursivité est moins courante dans awk que dans les langages généralistes, mais elle fonctionne correctement et est disponible dans toutes les implémentations majeures.

L’exemple ci-dessous définit une fonction récursive repeat(s, n) et l’utilise pour tracer des lignes de séparation qui correspondent automatiquement à la largeur de la ligne de données la plus large — aucun tiret codé en dur n’est nécessaire.

  • Évitez les récursions profondes avec des données d’entrée volumineuses — awk n’effectue pas d’optimisation des appels terminaux.
  • Pour une simple répétition, sprintf("%*s", n, "") associé à gsub(/ /, "-") est plus rapide, mais moins pédagogique.
#!/usr/bin/env bash
# Recursive repeat() to build separator lines dynamically
awk '
function repeat(s, n,    acc) {
    if (n <= 0) return ""
    acc = s repeat(s, n-1)
    return acc
}
BEGIN {
    header = sprintf("%-15s %10s %10s", "Metric", "Current", "Target")
    sep    = repeat("-", length(header))
    print sep
    print header
    print sep
    printf "%-15s %10.1f %10.1f\n", "CPU %",     72.4, 60.0
    printf "%-15s %10.1f %10.1f\n", "Mem GB",    14.2, 16.0
    printf "%-15s %10d %10d\n",   "Open FDs", 1024,  800
    print sep
}
' /dev/null

Utiliser printf avec un fichier ou un pipeline dans awk

Le printf d’awk (ainsi que print) peut rediriger la sortie vers des fichiers ou l’envoyer dans des commandes de l’interpréteur — directement depuis le programme awk, sans encapsuler l’ensemble dans un sous-interpréteur.

  • printf "..." > "file.txt" — écrit dans un fichier (le tronque une fois, puis ajoute les données pendant la même exécution).
  • printf "..." >> "file.txt" — ajoute des données à un fichier.
  • printf "..." | "sort -rn" — envoie les données dans une commande de l’interpréteur ; awk conserve le pipeline ouvert entre les enregistrements et le ferme à la fin du programme.

Un modèle courant consiste à diviser un seul parcours d’un journal en plusieurs fichiers de sortie, par état ou par hôte, afin d’éviter de parcourir plusieurs fois un fichier volumineux.

#!/usr/bin/env bash
# Route records into per-status files using print redirection
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

printf '200 /index.html\n404 /missing\n200 /api/data\n500 /crash\n404 /lost\n' | awk -v out="$tmpdir" '
{
    file = out "/" $1 ".log"
    printf "%-6s %s\n", $1, $2 > file
}
END {
    close(file)  # flush all open handles
}
'

echo "=== 200 ==="
cat "$tmpdir/200.log"
echo "=== 404 ==="
cat "$tmpdir/404.log"

Générer un rapport CSV avec awk

Tous les rapports ne sont pas destinés à être lus par des personnes. Parfois, la sortie doit être un CSV lisible par une machine, destiné à alimenter un tableur ou un pipeline en aval. Le printf d’awk gère cela simplement : définissez OFS avec une virgule ou contrôlez explicitement chaque séparateur.

Deux règles importantes pour produire un CSV robuste avec awk :

  • Entourez de guillemets doubles les champs susceptibles de contenir des virgules ou des retours à la ligne.
  • Échappez tout guillemet double littéral à l’intérieur d’un champ en le doublant : He said ""hello"".

La fonction csv_field(s) ci-dessous encapsule cette logique de mise entre guillemets afin qu’elle soit appliquée uniformément à chaque champ de type chaîne.

#!/usr/bin/env bash
# Emit a valid CSV report from space-separated input
printf 'alice engineer 95000\nbob "sales,mgr" 82000\ncarol developer 110000\n' | awk '
function csv_field(s,    safe) {
    safe = s
    gsub(/"/, "\"\"" , safe)   # double any embedded quotes
    return "\"" safe "\""       # wrap in quotes
}
BEGIN { print "Name,Role,Salary" }
{
    printf "%s,%s,%d\n", csv_field($1), csv_field($2), $3
}
'

De bout en bout : un rapport complet de journal d’accès

Cet exemple final rassemble tous les éléments : fonctions définies par l’utilisateur, mise en forme avec printf, accumulation dans des tableaux et en-tête/pied de page structurés. Les données d’entrée sont un journal d’accès Web simplifié ; la sortie est un tableau récapitulatif lisible par une personne, avec des totaux par méthode et une ligne de total général.

Techniques principales utilisées :

  • count[method]++ et bytes[method] += size accumulent les statistiques par méthode en un seul parcours.
  • human_bytes() (présente dans une scène précédente) convertit les totaux d’octets.
  • L’utilisation de printf avec des largeurs correspondantes dans l’en-tête, les données et le pied de page garantit l’alignement du tableau, quelle que soit la taille des données d’entrée.
  • Le bloc END parcourt le tableau avec for (k in arr) et produit une sortie triée via un pipeline vers sort.
#!/usr/bin/env bash
# Full access log report: method breakdown with human-readable bytes
printf 'GET /index 200 4096\nPOST /api 201 512\nGET /img 200 102400\nDELETE /item 204 0\nPOST /login 401 256\nGET /style 200 8192\n' | awk '
function human_bytes(n,    s) {
    if (n >= 1048576) s = sprintf("%.1f MB", n/1048576)
    else if (n >= 1024) s = sprintf("%.1f KB", n/1024)
    else s = sprintf("%d B", n)
    return s
}
{
    method = $1
    size   = $4
    count[method]++
    bytes[method] += size
    grand_count++
    grand_bytes += size
}
END {
    fmt = "%-10s %8s %15s\n"
    sep = "----------------------------------"
    printf fmt, "Method", "Requests", "Bytes"
    print sep
    for (m in count)
        printf "%-10s %8d %15s\n", m, count[m], human_bytes(bytes[m])
    print sep
    printf "%-10s %8d %15s\n", "TOTAL", grand_count, human_bytes(grand_bytes)
}
'

Vérification des connaissances : variables locales dans les fonctions awk

Laquelle des déclarations suivantes déclare correctement result comme variable locale à l’intérieur d’une fonction awk, conformément à la convention POSIX ?

Récapitulatif de la leçon : fonctions awk, printf et génération de rapports

Dans cette leçon, vous avez appris à écrire des programmes awk de qualité professionnelle qui génèrent des rapports mis en forme à partir de flux de données brutes. Voici les notions à retenir :

  • Les fonctions définies par l’utilisateur sont déclarées avec function name(params, locals). Les espaces supplémentaires avant les paramètres des variables locales correspondent à la convention POSIX — il n’existe pas de mot-clé local.
  • printf permet de contrôler précisément la sortie : largeur (%10s), alignement (%-10s) et précision (%8.2f). N’oubliez pas d’ajouter explicitement \n.
  • Utilisez BEGIN pour produire les en-têtes et les séparateurs, les règles par enregistrement pour accumuler les données, et END pour calculer les totaux et afficher le rapport terminé.
  • Redirigez la sortie de printf vers des fichiers (> file) ou des pipelines (| "sort") depuis awk pour diviser les rapports ou post-traiter la sortie.
  • Entourez les champs de type chaîne avec une fonction auxiliaire csv_field() lors de la production d’un CSV, afin de gérer sans risque les virgules et les guillemets intégrés.
  • Les fonctions qui convertissent les unités (human_bytes), répètent les caractères (repeat) ou assainissent les chaînes (trim, csv_field) méritent d’être conservées dans votre bibliothèque awk personnelle — elles se combinent facilement d’un projet à l’autre.
Gratuit pour commencer

Apprends DevOps Bootcamp avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
142
Leçons
568

Questions Fréquemment Posées

La leçon « Fonctions awk, mise en forme avec printf et génération de rapports » est-elle gratuite ?

Oui — le texte complet de « Fonctions awk, mise en forme avec printf et génération de rapports » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours DevOps Bootcamp, passe à CoddyKit PRO. Le cours DevOps Bootcamp comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Fonctions awk, mise en forme avec printf et génération de rapports » ?

Définissez des fonctions utilisateur et utilisez printf pour produire des rapports tabulaires soignés à partir de flux de données brutes. Tu pratiques DevOps Bootcamp avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer DevOps Bootcamp ?

Aucune expérience préalable n'est requise. DevOps Bootcamp sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Fonctions awk, mise en forme avec printf et génération de rapports » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon DevOps Bootcamp ?

Oui. Chaque leçon DevOps Bootcamp inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Enregistrements, champs et séparateurs personnalisés dans awk
  2. Motifs, plages et blocs BEGIN/END
  3. Agrégation avec les tableaux et le regroupement dans awk
  4. Fonctions awk, mise en forme avec printf et génération de rapports
← Retour à DevOps Bootcamp