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 avecprint $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 quecat fichier
).awk '/2/ {print $0}' fichier
: affiche toutes les lignes où le caractère 2 est présent (idem quegrep '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 (idemcut -d : -f 1 /etc/passwd
).awk 'BEGIN {FS = ":"}{print $1}' /etc/passwd
: idem que la précédente commandeawk '{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.