Choses à faire

24h dans une journée, et tant de choses à faire !

Awk : Premiers pas

publié le 26 octobre 2009 par Pierre Quillery

Awk est un vieil outil *nix qui peut, aujourd’hui encore, nous rendre bien des services pour ce qui est de manipuler des fichiers de données tabulaires, ce qu’il fait à la perfection. Voyons dans cet article comment approcher la programmation de cette commande.

Il y a quelques jours, j’ai pu constater dans le cadre de mon travail l’efficacité et la rapidité de cet outil : nous disposons d’un flux qui nous est mis à disposition par un partenaire ; à nous de le récupérer, et de le rendre « intégrable » dans la base MySQL.

Au départ la solution développée ne reposait pas du tout sur ces commandes, mais quasi-exclusivement sur des feuilles de traitement XSLT. Le traitement durait alors près de 36 minutes pour chaque flux, ce qui rendait les tests et les modifications difficiles.

Il a donc été décidé de refondre ces traitements en employant Awk. Après quelques optimisations, le script, écrit en très peu de temps, a permis de descendre autour de quelques secondes de traitement.

Un peu d’histoire

Awk est un très vieil outil *nix, il est apparu pour la première fois en … 1987 sur System V. Il a été révisé plusieurs fois et existe en plusieurs moutures sur toutes les distributions : awk, gawk, nawk … C’est à peu près le même combat, à quelques différences près (plus de fonctions sont disponibles dans gawk, par exemple). En un mot, il permet de faciliter le traitement de fichiers textes contenant des données tabulaires.

Awk ?

Il s’agit d’un véritable langage de programmation miniature qui contient tout ce dont vous avez besoin pour manipuler des chaînes et, à l’intérieur, des champs. Le principe de base est que vous ciblez une ligne (ou un groupe de ligne, ou toutes les lignes) à l’aide d’une expression régulière et que vous appliquez sur chacune des lignes un traitement particulier. Vous avez également pour compléter ce modèle de traitement la possibilité de définir un traitement à effectuer une seule fois au début (BEGIN) et à la fin du script (END).

L’avantage d’utiliser Awk plutôt qu’un autre langage de script n’est pas qu’une question de performances : grâce à lui et son intégration à *nix, vous bénéficiez également de la possibilité d’utiliser des pipes et autres redirections de flux.

Exemple d’utilisation : un CSV vers un tableau HTML

Plutôt que de transformer un fichier XML en données CSV, je me propose plutôt de montrer ici comment convertir de la façon la plus générique possible un fichier CSV vers un tableau HTML.

Voici tout d’abord la ligne qui me permet d’invoquer la commande Awk en précisant le fichier de script à utiliser (csvtohtml.awk) ainsi le fichier sur lequel il doit travailler (donnees.csv). Enfin, je redirige la sortie standard vers le fichier donnees.html.

gawk -f csvtohtml.awk donnees.csv > donnees.html

Rien de bien sorcier jusqu’ici, reste maintenant à définir le contenu de notre fichier de script, csvtohtml.awk qui va effectuer le fameux traitement.

############################################################
# Définition du pré-traitement
############################################################
BEGIN {
  # Field Separator : dans notre cas, un point-virgule
  FS=";"
  # On démarre l'affichage du tableau HTML
  print "<table>"
}

############################################################
# Fonction pour convertir une ligne du fichier en une ligne
# de tableau HTML.
# @param type (td/th) Suivant le type de ligne à générer
############################################################
function ligne_html(type) {
  retour = "<tr>"
  # Pour chaque champ de la ligne courante ...
  for ( i = 1 ; i < NF ; i++ ) {
    # On récupère ce qui se trouve entre les guillemets
    # qui encapsulent éventuellement le champ
    # On place le résultat dans le tableau r.
    match($i,/^[\"]?([^\"]*)/,r)
    # On concatène tout ça à la variable de retour
    # Le champ 1 de r contient ce qu'on a trouvé 
    # précédemment.
    retour = retour "<" type ">" r[1] "</" type ">"
  }
  return retour "</tr>"
}

###########################################################
# Définition du traitement global 
# (appliqué à toutes les lignes)
###########################################################
{
  # Si le Number of Record est à un, il nous faut traiter
  # le case de la première ligne, celle qui contient les 
  # entêtes.
  if ( NR == 1 ) {
    # On génère une ligne de table headers et on ouvre
    # le corps du tableau.
    print "<thead>" ligne_html("th") "</thead><tbody>"
  } else {
    # Pour toutes les autres lignes, on génère des td.
    print ligne_html("td")
  }
}

############################################################
# Définition du post-traitement
############################################################
END {
  # On termine le tableau ... C'est fini 🙂 !
  print "</tbody></table>"
}

Si vous souhaitez approfondir le sujet, je ne peux que vous diriger sur le petit opuscule « Sed & Awk (2nd Edition) » de Arnold Robbis, publié chez O’Reilly (vous pouvez l’avoir sur Amazon pour 5€ avec les frais de port, c’est une affaire).

Les textes, illustrations et démonstrations présents sur ce site sont la propriété de leurs auteurs respectifs, sauf mention contraire (photo de la bannière).
Chosesafaire.fr, un site propulsé par Wordpress, vous est proposé par Pierre Quillery & Killian Ebel.

Valid XHTML 1.0 Strict