AWK traitement de fichier texte

La commande unix awk permet des manipulations avancées sur les chaînes de caractères.

awk [options] [programme] [fichier]

L’option la plus courante est -F : séparateur de champ

La structure du programme est la suivante :
'motif1 { action1 }
motif2 { action2 } …'

motif (en anglais pattern) est la condition pour réaliser l’action. On utilise le plus souvent une expression régulière.

Exemple 1 : condition

avec un fichier ASCII “input.xyz” de la forme suivante (données Lidar) :

13.83535621 42.12214528 401.940 32 2
13.83534713 42.12213870 401.870 28 2
13.83533818 42.12213222 401.670 33 2
13.83532879 42.12211645 401.950 30 1
13.83533763 42.12212258 401.630 28 2
13.83534682 42.12212933 401.830 29 2
13.83535625 42.12213609 402.250 25 1

on veut ne conserver que les lignes où la 5ème colonne est différente de 1

awk '{ if ( $5!=1 ) print $0 }' input.xyz > output.xyz

et voilà! c’est tout

Exemple 2 : utilisation dans un script

on a un fichier texte avec différents espacements entre colonne, parfois un espace, parfois plusieurs. C’est le cas des fichiers en sortie du logiciel Circé IGN qui sont formattés vraiment bizarrement. Il contiennent parfois un et parfois plein d’espaces entre les champs, et des lignes d’entête qui commencent par *! , voici un extrait d’un fichier en sortie de Circé.

*!COORDONNÉES: projetées
*!ELLIPSOÏDE: GRS 1980
*!PROJECTION: LAMBERT-93
*!REPERE VERTICAL: IGN69
*!
*! id E N H geod.prec. vert.prec.
point1 830488.865    6252042.364 0.558 -1.167384     542.6 no info 5 / 10 cm
point2 831546.415    6251863.871 6.043 -1.176810     544.3 no info 5 / 10 cm

Voici la manip pour reformatter cela simplement avec awk au sein d’un script.

#! /bin/bash

awk '$1!~/*!/ {$1=$1;print $0}' OFS=, > out.csv

pour utiliser le script, on tape simplement: cat input.txt | ./script.sh

encore une fois, c’est tout!

Quelques explications :

  • la variable $1 correspond au premier champ de l’enregistrement,
  • la variable $0 correspond à tout l’enregistrement,
  • la variable définie par OFS correspond au séparateur de champ voulu en sortie, ici on définie une virgule
  • L’action {$1=$1;print $0}effectue d’abord un calcul de champ avec $1=$1, ici on affecte au premier champ la valeur du premier champ. Donc on ne fait rien dans ce calcul, mais cela a pour effet de ré-écrire tout l’enregistrement avec le séparateur de champ voulu (par défaut un espace), et ainsi cela supprime tous les espaces superflus entre les champs et en début et fin d’enregistrement. Et ensuite avec print $0  on écrie tout l’enregistrement dans la sortie standard.
  • Le motif $1!~/*!/ sélectionne tous les enregistrements dont le premier champ ne contient pas à la chaîne de caractères *!

Exemple 3 : supprimer tous les espaces superflus

awk '{$1=$1}1' input.csv > output.csv

  • L’action {$1=$1} voir Exemple 2 ci-dessus
  • Le 1 situé après les accolades {} est un motif correspondant à Vrai, et lorsqu’il n’y a pas d’action située après le motif c’est l’action par défaut print qui est executée, donc chaque ligne est écrite dans la sortie standard.

Exemple 4 : chaîner les commandes en bash

exemple tiré de https://www.the-art-of-web.com/system/imagemagick-watermark/

ls -1 photos/process_*.jpg | awk -F\/ '{print "composite -gravity SouthEast -dissolve 50% -resize 400 watermark.png photos/"$(NF)" watermarked/"$(NF)}' | sh

Cette commande permet d’ajouter une trame en surimpression (watermark) sur toute une série d’images de façon automatique avec l’outil “composite” (un des outils d’Imagemagick). awk sert ici à écrire la commande de “composite” avec tous les fichiers renvoyés par la commande “ls …”.

Cet exemple est intéressant car on voit bien l’intérêt de awk pour scripter des tâches. On chaîne ici trois commandes avec des pipes. La première liste les photos correspondant à un certain pattern, la seconde écrit une commande “composite” et la troisième exécute cette commande “composite”.

Quelques exemples tirés de la page Wikipedia

  • awk '{print $0}' fichier : affiche toutes les lignes de fichier (idem que cat fichier).
  • awk '/2/ {print $0}' fichier : affiche toutes les lignes où le caractère 2 est présent (idem que grep '2' ref.txt).
  • awk '$1~/2/ {print $0}' fichier : affiche toutes les lignes où le caractère 2 est présent dans le premier champ.
  • awk '{print NR ":", $0}' fichier : affiche le contenu de fichier, mais chaque ligne est précédée de son numéro.
  • awk -F: '{print $1}' /etc/passwd : renvoie la liste des utilisateurs (idem cut -d : -f 1 /etc/passwd).
  • awk 'BEGIN {FS = ":"}{print $1}' /etc/passwd : idem que la précédente commande
  • awk '{s=s+$1} END {print s, s/NR}' fichier : écrit la somme et la moyenne de tous les nombres de la première colonne de fichier.
  • awk '/Motif1/ , /Motif2/' fichier : écrit toutes les lignes contenues dans le fichier entre le Motif1 et le Motif2.

References: