Commande Linux awk : Traitement de texte

LinuxBeginner
Pratiquer maintenant

Introduction

Bienvenue dans l'univers du traitement de texte avec AWK. Dans ce laboratoire, vous apprendrez à utiliser la commande awk pour analyser des fichiers journaux (logs), une tâche courante pour les administrateurs système et les analystes de données. AWK est un outil puissant pour traiter des données textuelles structurées sous Linux, vous permettant d'extraire, de filtrer et de transformer des informations efficacement.

Imaginez que vous êtes un administrateur système junior chargé d'analyser les journaux du serveur pour identifier des menaces de sécurité potentielles et des problèmes de performance. La commande awk sera votre outil principal pour cette tâche, vous permettant de parcourir rapidement de gros fichiers journaux et d'en extraire des informations pertinentes.

Examen du fichier journal

Commençons par examiner le contenu de notre fichier journal d'exemple. Ce fichier contient des journaux d'accès au serveur simulés que nous analyserons tout au long de ce laboratoire.

Tout d'abord, accédez au répertoire du projet :

cd ~/project

Maintenant, affichons les premières lignes du fichier journal :

head -n 5 server_logs.txt

Vous devriez voir une sortie similaire à celle-ci :

2023-08-01 08:15:23 192.168.1.100 GET /index.html 200
2023-08-01 08:16:45 192.168.1.101 GET /about.html 200
2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 08:18:12 192.168.1.103 GET /products.html 404
2023-08-01 08:19:05 192.168.1.104 GET /services.html 200

Ce fichier journal contient des informations sur les requêtes serveur, notamment la date et l'heure, l'adresse IP, la méthode HTTP, la ressource demandée et le code d'état.

Utilisation de base d'AWK - Affichage de champs spécifiques

Maintenant que nous avons vu la structure de notre fichier journal, utilisons AWK pour extraire des informations spécifiques. Par défaut, AWK divise chaque ligne en champs basés sur les espaces. Nous pouvons faire référence à ces champs en utilisant $1, $2, etc., où $1 est le premier champ, $2 le deuxième, et ainsi de suite.

Extrayons les adresses IP (le troisième champ) de notre fichier journal :

awk '{print $3}' server_logs.txt | head -n 5

Vous devriez voir une sortie similaire à celle-ci :

192.168.1.100
192.168.1.101
192.168.1.102
192.168.1.103
192.168.1.104

Dans cette commande :

  • awk '{print $3}' indique à AWK d'imprimer le troisième champ de chaque ligne.
  • Nous redirigeons (|) la sortie vers head -n 5 pour limiter l'affichage aux 5 premières lignes.

Maintenant, imprimons à la fois l'adresse IP et la ressource demandée :

awk '{print $3, $5}' server_logs.txt | head -n 5

Sortie :

192.168.1.100 /index.html
192.168.1.101 /about.html
192.168.1.102 /login.php
192.168.1.103 /products.html
192.168.1.104 /services.html

Ici, nous imprimons le troisième champ (adresse IP) et le cinquième champ (ressource demandée) pour chaque ligne.

Filtrage des entrées de journal

L'une des forces d'AWK est sa capacité à filtrer les données en fonction de conditions. Utilisons cette fonctionnalité pour trouver toutes les requêtes POST dans notre fichier journal, car elles pourraient être plus sensibles en termes de sécurité que les requêtes GET.

Exécutez la commande suivante :

awk '$4 == "POST" {print $0}' server_logs.txt

Cette commande peut imprimer des centaines de lignes car le fichier d'exemple contient 5 000 entrées de journal. Si vous souhaitez seulement inspecter un échantillon gérable pendant votre apprentissage, ajoutez | head -n 10 :

awk '$4 == "POST" {print $0}' server_logs.txt | head -n 10

La vérification accepte toujours la commande awk simple, utilisez donc la version qui vous aide à lire la sortie plus confortablement.

Décomposons la syntaxe de cette commande pour comprendre comment fonctionne le filtrage AWK :

  1. $4 == "POST" - Il s'agit d'un motif ou d'une condition qu'AWK évalue pour chaque ligne :

    • $4 fait référence au quatrième champ de la ligne actuelle (dans notre fichier journal, il s'agit de la méthode HTTP)
    • == est l'opérateur d'égalité qui vérifie si deux valeurs sont identiques
    • "POST" est la chaîne de caractères avec laquelle nous comparons
  2. {print $0} - C'est l'action qu'AWK effectue lorsque la condition est vraie :

    • Les accolades {} entourent l'action
    • print est la commande pour afficher du texte
    • $0 représente la ligne entière actuelle (tous les champs)

La structure de la commande suit le modèle AWK : condition {action}. AWK lit chaque ligne, et si la condition est évaluée comme vraie, il effectue l'action. Si aucune condition n'est spécifiée (comme dans nos exemples précédents), l'action est effectuée pour chaque ligne.

Vous devriez voir une sortie similaire à celle-ci :

2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 09:23:45 192.168.1.110 POST /submit_form.php 200
2023-08-01 10:45:12 192.168.1.115 POST /upload.php 500

Maintenant, trouvons toutes les requêtes ayant abouti à un code d'état 404 (Non trouvé) :

awk '$6 == "404" {print $1, $2, $5}' server_logs.txt

Cette commande suit le même modèle mais avec des valeurs différentes :

  • La condition $6 == "404" vérifie si le sixième champ (code d'état) est égal à 404
  • L'action {print $1, $2, $5} n'imprime que des champs spécifiques :
    • $1 - Premier champ (date)
    • $2 - Deuxième champ (heure)
    • $5 - Cinquième champ (ressource demandée)

Cette impression sélective vous permet de vous concentrer uniquement sur les informations dont vous avez besoin.

Sortie :

2023-08-01 08:18:12 /products.html
2023-08-01 09:30:18 /nonexistent.html
2023-08-01 11:05:30 /missing_page.html

Vous pouvez combiner plusieurs conditions en utilisant des opérateurs logiques :

  • && pour ET (les deux conditions doivent être vraies)
  • || pour OU (au moins une condition doit être vraie)
  • ! pour NON (négation d'une condition)

Par exemple, pour trouver toutes les requêtes POST ayant abouti à une erreur (code d'état >= 400) :

awk '$4 == "POST" && $6 >= 400 {print $0}' server_logs.txt

Ces filtres peuvent vous aider à identifier rapidement des problèmes potentiels ou des activités suspectes dans vos journaux serveur.

Comptage et synthèse des données

AWK est excellent pour compter les occurrences et synthétiser des données. Utilisons-le pour compter le nombre de requêtes pour chaque code d'état HTTP.

Exécutez cette commande :

awk '{count[$6]++} END {for (code in count) print code, count[code]}' server_logs.txt | sort -n

Cette commande est plus complexe, décomposons-la étape par étape :

  1. {count[$6]++} - C'est l'action principale effectuée pour chaque ligne :

    • count est un tableau (tableau associatif ou dictionnaire) que nous créons
    • [$6] utilise la valeur du 6ème champ (code d'état) comme index/clé du tableau
    • ++ est l'opérateur d'incrémentation, ajoutant 1 à la valeur actuelle
    • Ainsi, pour chaque ligne, nous incrémentons le compteur pour le code d'état spécifique trouvé
  2. END {for (code in count) print code, count[code]} - Ceci est exécuté après le traitement de toutes les lignes :

    • END est un motif spécial qui correspond à la fin de l'entrée
    • {...} contient l'action à effectuer une fois que toute l'entrée a été traitée
    • for (code in count) est une boucle qui parcourt toutes les clés du tableau count
    • print code, count[code] imprime chaque code d'état et son nombre d'occurrences
  3. | sort -n - Redirige la sortie vers la commande sort, qui trie numériquement

Lorsqu'AWK traite un tableau comme count[$6]++, il effectue automatiquement les opérations suivantes :

  • Crée le tableau s'il n'existe pas
  • Crée un nouvel élément avec la valeur 0 si la clé n'existe pas
  • Puis incrémente la valeur de 1

Vous devriez voir une sortie similaire à celle-ci :

200 3562
301 45
302 78
304 112
400 23
403 8
404 89
500 15

Ce résumé vous montre rapidement la distribution des codes d'état dans votre fichier journal.

Maintenant, trouvons les 5 ressources les plus fréquemment consultées :

awk '{count[$5]++} END {for (resource in count) print count[resource], resource}' server_logs.txt | sort -rn | head -n 5

Cette commande suit un modèle similaire avec quelques changements :

  1. {count[$5]++} - Compte les occurrences du 5ème champ (la ressource demandée)
  2. END {for (resource in count) print count[resource], resource} - Après le traitement de toutes les lignes :
    • Imprime le nombre d'abord, suivi de la ressource
    • Cet ordre facilite le tri numérique par nombre d'occurrences
  3. | sort -rn - Trie numériquement dans l'ordre inverse (les nombres les plus élevés en premier)
  4. | head -n 5 - Limite la sortie aux 5 premières lignes (top 5 des résultats)

Sortie :

1823 /index.html
956 /about.html
743 /products.html
512 /services.html
298 /contact.html

Ces commandes AWK démontrent la puissance de l'utilisation des tableaux pour le comptage et la synthèse. Vous pouvez adapter ce modèle pour compter n'importe quel champ ou combinaison de champs dans vos données.

Par exemple, pour compter le nombre de requêtes par adresse IP :

awk '{count[$3]++} END {for (ip in count) print ip, count[ip]}' server_logs.txt

Pour compter les requêtes à la fois par méthode et par état :

awk '{key=$4"-"$6; count[key]++} END {for (k in count) print k, count[k]}' server_logs.txt

Ces résumés peuvent vous aider à comprendre les modèles de trafic et à identifier les ressources populaires (ou problématiques) sur votre serveur.

Création d'un rapport simple

Pour notre tâche finale, créons un rapport HTML simple résumant certaines informations clés de notre fichier journal. Nous utiliserons un script AWK stocké dans un fichier séparé pour cette opération plus complexe.

Cette étape combine plusieurs idées AWK vues dans les sections précédentes :

  • des compteurs tels que total++
  • des tableaux tels que ip_count[$3]++
  • un bloc END qui imprime le résumé final

Si le script semble long au premier abord, concentrez-vous sur un bloc à la fois. Vous n'avez pas besoin de mémoriser tout le fichier avant de l'exécuter.

Tout d'abord, créez un fichier nommé log_report.awk avec le contenu suivant :

Astuces : Copiez le contenu ci-dessous et collez-le dans votre terminal pour créer le fichier.

cat << 'EOF' > log_report.awk
BEGIN {
    print "<html><body>"
    print "<h1>Server Log Summary</h1>"
    total = 0
    errors = 0
}

{
    total++
    if ($6 >= 400) errors++
    ip_count[$3]++
    resource_count[$5]++
}

END {
    print "<p>Total requests: " total "</p>"
    print "<p>Error rate: " (errors/total) * 100 "%</p>"
    
    print "<h2>Top 5 IP Addresses</h2>"
    print "<ul>"
    for (ip in ip_count) {
        top_ips[ip] = ip_count[ip]
    }
    n = asort(top_ips, sorted_ips, "@val_num_desc")
    for (i = 1; i <= 5 && i <= n; i++) {
        for (ip in ip_count) {
            if (ip_count[ip] == sorted_ips[i]) {
                print "<li>" ip ": " ip_count[ip] " requests</li>"
                break
            }
        }
    }
    print "</ul>"
    
    print "<h2>Top 5 Requested Resources</h2>"
    print "<ul>"
    for (resource in resource_count) {
        top_resources[resource] = resource_count[resource]
    }
    n = asort(top_resources, sorted_resources, "@val_num_desc")
    for (i = 1; i <= 5 && i <= n; i++) {
        for (resource in resource_count) {
            if (resource_count[resource] == sorted_resources[i]) {
                print "<li>" resource ": " resource_count[resource] " requests</li>"
                break
            }
        }
    }
    print "</ul>"
    
    print "</body></html>"
}
EOF

Comprenons ce script AWK section par section :

  1. Bloc BEGIN : S'exécute avant de traiter toute ligne d'entrée

    BEGIN {
        print "<html><body>"  ## Début de la structure HTML
        print "<h1>Server Log Summary</h1>"
        total = 0  ## Initialiser le compteur pour le total des requêtes
        errors = 0  ## Initialiser le compteur pour les requêtes en erreur
    }
  2. Bloc de traitement principal : S'exécute pour chaque ligne du fichier d'entrée

    {
        total++  ## Incrémenter le compteur total de requêtes
        if ($6 >= 400) errors++  ## Compter les réponses d'erreur (codes d'état >= 400)
        ip_count[$3]++  ## Compter les requêtes par adresse IP (champ 3)
        resource_count[$5]++  ## Compter les requêtes par ressource (champ 5)
    }
  3. Bloc END : S'exécute après le traitement de toutes les lignes d'entrée

    END {
        ## Imprimer les statistiques de résumé
        print "<p>Total requests: " total "</p>"
        print "<p>Error rate: " (errors/total) * 100 "%</p>"
    
        ## Traiter et imprimer les 5 meilleures adresses IP
        ## ...
    
        ## Traiter et imprimer les 5 meilleures ressources demandées
        ## ...
    
        print "</body></html>"  ## Fin de la structure HTML
    }

Avant de continuer, notez le flux global :

  1. BEGIN imprime les balises HTML d'ouverture et initialise les compteurs.
  2. Le bloc central traite chaque ligne de journal et met à jour les totaux.
  3. END imprime le rapport final après que chaque ligne a été analysée.

Examinons la logique de tri pour les meilleures IP (la section des ressources fonctionne de la même manière) :

## Copier les comptes dans un nouveau tableau pour le tri
for (ip in ip_count) {
    top_ips[ip] = ip_count[ip]
}

## Trier le tableau par valeur dans l'ordre décroissant
n = asort(top_ips, sorted_ips, "@val_num_desc")

## Imprimer les 5 meilleures entrées
for (i = 1; i <= 5 && i <= n; i++) {
    ## Trouver l'IP originale qui correspond à ce compte
    for (ip in ip_count) {
        if (ip_count[ip] == sorted_ips[i]) {
            print "<li>" ip ": " ip_count[ip] " requests</li>"
            break
        }
    }
}

Dans ce script :

  • La fonction asort() trie le tableau
  • "@val_num_desc" est un argument spécial qui lui indique de trier numériquement par valeur dans l'ordre décroissant
  • Les boucles imbriquées trouvent et impriment les 5 meilleures entrées

Vous pouvez concevoir les boucles imbriquées comme ceci :

  • la première boucle décide quels comptes appartiennent au top 5
  • la seconde boucle trouve quelle adresse IP ou ressource a produit chaque compte

Ce modèle de recherche est plus avancé que les étapes précédentes, il est donc normal si c'est la première partie du laboratoire qui ressemble à de la vraie programmation plutôt qu'à une commande d'une ligne.

Maintenant, exécutons notre script AWK pour générer le rapport :

awk -f log_report.awk server_logs.txt > log_report.html

L'option -f indique à AWK de lire le script à partir du fichier spécifié :

  • -f log_report.awk - Lit le script AWK à partir du fichier log_report.awk
  • server_logs.txt - Traite ce fichier en utilisant le script
  • > log_report.html - Redirige la sortie vers le fichier log_report.html

Vous pouvez visualiser le contenu du rapport en utilisant la commande cat :

cat log_report.html

Si la sortie HTML semble difficile à parcourir dans le terminal, prévisualisez d'abord seulement la première partie :

head -n 15 log_report.html

Ce rapport fournit un résumé du total des requêtes, du taux d'erreur, des 5 meilleures adresses IP et des 5 meilleures ressources demandées. Dans un scénario réel, vous pourriez ouvrir ce fichier HTML dans un navigateur web pour une vue formatée.

L'approche que nous avons utilisée dans ce script démontre comment AWK peut être utilisé pour des tâches d'analyse de données plus complexes. Vous pouvez étendre ce script pour inclure des statistiques supplémentaires ou différentes visualisations en fonction de vos besoins spécifiques.

Résumé

Félicitations ! Vous avez terminé ce laboratoire sur l'utilisation de la commande AWK pour l'analyse de journaux. Récapitulons ce que vous avez appris :

  1. Utilisation de base d'AWK : Impression de champs spécifiques à partir d'un fichier texte structuré.
  2. Filtrage des données : Utilisation de conditions dans AWK pour sélectionner des entrées de journal spécifiques.
  3. Comptage et synthèse : Utilisation d'AWK pour générer des statistiques à partir de données de journal.
  4. Création de rapports : Écriture de scripts AWK plus complexes pour générer des rapports formatés.

Ces compétences seront inestimables pour analyser des fichiers journaux, traiter des données et générer des rapports dans votre futur travail d'administrateur système ou d'analyste de données.

Voici quelques paramètres et fonctionnalités AWK supplémentaires que nous n'avons pas couverts dans ce laboratoire :

  • -F : Spécifie un séparateur de champ autre que l'espace.
  • -v : Assigne une valeur à une variable.
  • NR : Une variable intégrée représentant le numéro d'enregistrement actuel.
  • NF : Une variable intégrée représentant le nombre de champs dans l'enregistrement actuel.
  • Blocs BEGIN et END : Motifs spéciaux pour l'initialisation et la finalisation.
  • Fonctions intégrées : Fonctions mathématiques, fonctions de chaîne, et plus encore.

N'oubliez pas que la pratique est la clé pour maîtriser AWK. Essayez de modifier les commandes et les scripts de ce laboratoire pour analyser différents aspects du fichier journal ou pour traiter d'autres types de données textuelles structurées.

Ressources