Manipulation de fichiers texte avec sed, AWK et grep

Le but de cette mini-formation est d’introduire trois outils courants dans le monde POSIX pour traiter des fichiers texte. Ces outils sont disponibles sur toutes les distributions Linux, ainsi que sur MacOS et dans Windows Subsystem for Linux.

  • sed, un éditeur de flux de texte
  • AWK, un langage de programmation orienté par les données
  • grep, un outil de sélection d’enregistrements

Introduction

  • Nous avons souvent à travailler avec des données en format texte, que ce soit des fichiers CSV, du HTML ou des fichiers de journalisation de différents outils et systèmes.
  • Il peut être tentant de travailler avec des langages tels que R ou Python avec ce type de fichiers, mais ils sont limités par la mémoire. Parfois même, les fichiers ne sont pas lisibles par ces langages dus à des problèmes de bas niveau.
  • Les trois outils présentés fonctionnent à la volée, une ligne à la fois, avec des besoins en mémoire limités. Ils peuvent sans problème traiter des gigaoctets de données sur un ordinateur personnel.
  • Ils sont installés par défaut sur tout Linux et macOS, ce qui les rend faciles d’accès. Par contre, ils ne sont pas disponibles dans Windows.

sed

  • sed signifie Stream EDitor
  • C’est un logiciel assez simple, qui prend en argument une expression régulière et un fichier en entrée. Il retourne ses résultats à la sortie standard. On peut écrire cette sortie dans un fichier avec un chevron droit > ou la rediriger vers un autre programme avec un tube|.
  • Ce programme effectue principalement un « rechercher et remplacer ».

La syntaxe la plus utilisée est de la forme suivante :

sed -e 's/Ancien/Nouveau/g' nomFichierEntrée > nomFichierSortie

L’expression est composée de commandes (s pour substitution), de deux expressions régulières et de drapeaux (g pour global). La deuxième expression peut aussi inclure des références vers les groupes de la première expression.

Il est possible d’éditer sur place et de créer une copie de sauvegarde

sed -ibak 's/Ancien/Nouveau/g' nomFichierEntrée

awk

AWK est un langage de programmation orienté par les données. En fait, ce sont les données qu’on lui passe en entrée qui déterminent le flux d’exécution. Il sert entre autres à produire du code automatiquement selon un fichier de paramètres.

La version la plus utilisée d’AWK est GNU AWK, appelé avec la commande gawk.

Un programme prend la forme suivante :

awk [options] [programme] [fichier]

Les principales options utilisées sont :

  • -F: le séparateur de champs, utile pour lire un CSV par exemple
  • -f: le programme dans un fichier externe
  • -v: Initialiser des variables depuis l’environnement bash.

Le programme a la structure suivante : 'motif{action}motif{action}'

Le motif est soit une expression régulière, une variable ou un motif spécial : BEGIN ou END

grep

La commande grep provient de global regular expression print et permet de rechercher les lignes qui contiennent une certaine expression régulière dans un texte, un fichier ou un répertoire de fichiers.

Utilisé en combinaison avec d’autres commandes, c’est le principal outil de recherche des systèmes POSIX.

La syntaxe de grep est :

grep 'expression' fichiers

Exemples de manipulation de fichiers texte

Données

Nous travaillerons sur un extrait de texte libre : Amusements in Mathematics par Henry Ernest Dudeney
Il s’agit d’un recueil de problèmes mathématiques

wget https://ia800300.us.archive.org/27/items/amusementsinmath16713gut/16713.txt

Voici un aperçu du contenu, extrait avec ce programme que nous étudierons

cat 16713.txt | \
gawk 'BEGIN{count=1}/^9\.\-\-/{print "Extrait : "count" ";flag=1;count++;next}/^10\.\-\-/{flag=0}flag{print NR": "$0}' - | \
grep '^[Extrait|0-9]\+ :\s\w\+' | \
sed -E 's/L([0-9]*.?[0-9]+)/\1$/g'
Extrait : 1
399 : A man recently bought two aeroplanes, but afterwards found that they
400: would not answer the purpose for which he wanted them. So he sold them
401: for 600$ each, making a loss of 20 per cent. on one machine and a profit
402: of 20 per cent. on the other. Did he make a profit on the whole
403: transaction, or a loss? And how much?
Extrait : 2
11569 : The man must have paid 500$ and 750$ for the two machines, making
11570: together 1,250$; but as he sold them for only 1,200$, he lost 50$ by the
11571: transaction.

AWK

Explorons la première section de la commande :

gawk 'BEGIN{count=1}/^9\.\-\-/{print "Extrait : "count" ";flag=1;count++;next}/^10\.\-\-/{flag=0}flag{print NR" : "$0}' -

Le programme lié au motif BEGIN est exécuté avant la lecture du fichier en entrée.

  • Initialisation de la variable count à 1. Ce compteur sert à numéroter les différents extraits.

Ensuite, le programme parcourt le fichier ligne par ligne jusqu’à ce qu’il rencontre une des situations suivantes :

  • ^9\.\-\-
  • ^10\.\-\-
  • la variable flag vaut 1

À ce moment, il exécutera le code associé à chacune d’elles. Dans le premier cas, il imprimera le numéro de l’extrait print "Extrait : "count" ", mettra l’indicateur flag=1 et incrémentera le compteur count++.

Pendant que la variable flag vaut 1, les lignes sont imprimées, incluant le numéro de la ligne au début, représenté par la variable NR.

Lorsque la deuxième expression est rencontrée, le flag reprend la valeur 0 et les lignes cessent d’être imprimées. Ce programme permet donc d’extraire tous les blocs de texte inclus entre des lignes commençant par 9.-- et 10.--. Dans notre cas, il s’agit du problème # 9 et de sa solution.

La sortie obtenue est la suivante :

Extrait : 1
398 :
399 : A man recently bought two aeroplanes, but afterwards found that they
400: would not answer the purpose for which he wanted them. So he sold them
401: for L600 each, making a loss of 20 per cent. on one machine and a profit
402: of 20 per cent. on the other. Did he make a profit on the whole
403: transaction, or a loss? And how much?
404:
405:
Extrait : 2
11568 :
11569 : The man must have paid L500 and L750 for the two machines, making
11570: together L1,250; but as he sold them for only L1,200, he lost L50 by the
11571: transaction.
11572:
11573:

grep

Explorons maintenant la deuxième expression :

grep '^[Extrait|0-9]\+:\s\w\+'

Cette expression sert à conserver les lignes qui ne sont pas vides, c’est-à-dire contenant au moins un mot \w+ après le numéro de ligne ou le mont Extrait, et la séquence : \s . C’est donc un filtre sur les lignes qui nous permet d’obtenir :

Extrait : 1
399 : A man recently bought two aeroplanes, but afterwards found that they
400: would not answer the purpose for which he wanted them. So he sold them
401: for L600 each, making a loss of 20 per cent. on one machine and a profit
402: of 20 per cent. on the other. Did he make a profit on the whole
403: transaction, or a loss? And how much?
Extrait : 2
11569 : The man must have paid L500 and L750 for the two machines, making
11570: together L1,250; but as he sold them for only L1,200, he lost L50 by the
11571: transaction.

Lorsque la commande est exécutée dans un terminal supportant les couleurs, les chaines de caractères correspondant à l’expression recherchée seront en couleur.

Exemple d'utilisation de AWK et de grep pour faire une manipulation de fichier texte, avec de la couleur

sed

Explorons enfin la dernière commande :

sed -E 's/L([0-9]*.?[0-9]+)/\1$/g'

Nous voulons remplacer les montants en livres pour des dollars.

Cette commande recherche un nombre décimal précédé de L. Nous voulons le remplacer par le même nombre, suivi d’un symbole de dollar $.

Le groupe que l’on désire identifier et conserver est placé entre parenthèses. C’est un groupe de capture. On peut ensuite rappeler ces groupes dans la substitution à l’aide des marqueurs de groupes \1... \9.


On obtient enfin

Extrait : 1
399 : A man recently bought two aeroplanes, but afterwards found that they
400: would not answer the purpose for which he wanted them. So he sold them
401: for 600$ each, making a loss of 20 per cent. on one machine and a profit
402: of 20 per cent. on the other. Did he make a profit on the whole
403: transaction, or a loss? And how much?
Extrait : 2
11569 : The man must have paid 500$ and 750$ for the two machines, making
11570: together 1,250$; but as he sold them for only 1,200$, he lost 50$ by the
11571: transaction.

Articles connexes