grep, cut, awk et compagnie

Première publication : 2011-01-06

C’est vraiment puissant et agréable d’utiliser des systèmes Linux/Unix. Voilà un nouvel exemple que je veux partager.

Contexte

Je souhaite quantifier le volume d’images transférées depuis un de mes serveurs. Le meilleur endroit pour trouver cette info me semble être les fichiers de logs d’Apache (ou autre serveur web) puisqu’ils indiquent l’URL demandée, le code HTTP et la taille du fichier transmis.

Une fois isolés les logs que je souhaite analyser, il ne me restait plus qu’à extraire les bons chiffres et en faire une somme.

Solution

grep '/system' * | grep -o -E '\b200 [0-9]+\b' | cut -f 2 -d ' ' | awk '{sum+=$0} END{print sum/1024/1024}'

Je vous décortique chaque étape du processus, séparées par le “pipe” (tuyau) qui sert à transmettre le résultat d’une commande à la suivante.

$ grep '/system' *

grep permet de lire le contenu d’un fichier ou d’un flux et d’en extraire des parties, selon des règles et filtres. Je lui demande donc de lire tous les fichiers logs (le * à la fin), à la recherche de “/system” (la base des URLs qui m’intéressent).

J’obtiens donc toutes les lignes de log où une URL qui contient “/system” a été demandée.

Exemple :

178.48.252.123 - - [12/Dec/2010:07:12:11 +0100] "GET /system/images/missing-sq128.jpg HTTP/1.1" 200 2237 "http://www.hotelhotel.com/stylesheets/hh.css?1291888120" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12"
$ grep -o -E '\\b200 \[0-9\]+\\b'

Les lignes sont analysées une nouvelle fois avec grep à la recherche d’une expression régulière qui permettra d’isoler les requêtes soldées par un code HTTP 200, indiquant que l’image a été effectivement téléchargée.

On utilise l’option -E pour indiquer qu’on veut les expressions régulières “étendues”. L’option -o indique qu’on ne veut renvoyer que ce qui a été capturé par l’expression, et pas tout la ligne.

L’expression indique qu’on souhaite capturer ce qui commence par “200”, précédé d’une rupture de mot (donc un espace, une ponctuation…), puis un espace, une suite de chiffres, et une rupture de mot.

Exemple : 200 2237

$ cut -f 2 -d ' '

cut permet de découper la chaîne de caractère et de renvoyer seulement certaines portions de cette chaîne.

L’option -d on indique qu’on veut découper selon les espaces. L’option -f indique qu’on veut renvoyer le 2ème segment (la taille de l’image)

Exemple : 2237

À ce stade, on obtient une série de ligne qui contiennent les tailles des images téléchargées, il reste à en faire la somme

$ awk '{sum+=$0} END{print sum/1024/1024}'

awk est un outil aussi génial que les autres utilisés ici, mais je le connais très mal. C’est Colin qui m’a proposé cette dernière commande.

On demande donc à awk de faire la somme des valeurs trouvées à chaque ligne, de renvoyer cette somme, préalablement convertie en mega-octets (dans les logs Apache, ce sont des octets)

Conclusion

J’ai donc pu faire des opérations pas trop complexes, mais pas non plus triviales, en une seule ligne et avec un résultat immédiat.

Encore fois, ça prouve que bien connaître ses outils permet de travailler efficacement.

Inutile de dire que j’ai passé plus de temps à écrire ce petit article que pour construire cet enchaînement de commande, avec tous les essais/erreurs.