AWK pour le fun

Table of Contents

Salut à toi ! Bienvenue dans la bidouille !

Utilise « C-c C-o » (control+c puis control+o) pour suivre les liens (les trucs soulignés en bleu ci-dessous).

Ce fichier est disponible à http://runtime.bordeaux.inria.fr/furmento/bidouille/awk.org.

1 Introduction

Awk est un langage qui permet de rechercher/sélectionner des lignes dans un ou plusieurs fichiers (ou à partir de l'entrée standard) pour leur appliquer un traitement. Ce langage permet donc de décrire:

des sélecteurs (de ligne)
ce sont des expressions qui décrivent les propriétés que doivent avoir les lignes que l'on recherche dans le ou les fichiers inspectés
des traitements
ils sont décrits au moyen d'un langage de programmation (fortement inspiré du langage C) qui permet d'utiliser des variables, des boucles, des tests, etc.

Pour associer un sélecteur à un traitement, il suffit d'écrire une ligne de la forme suivante:

sélecteur traitement

D'autre part, Awk décompose en champs chacune des lignes du fichier analysé ; ces champs sont placés dans les variables $1, $2, … ,$n (la variable $0 désignant toute la ligne).

Les champs successifs sont repérés par un délimiteur de champs. Comme c'est souvent le cas avec les commandes Unix, le délimiteur de champs par défaut est le caractère espace.

Enfin, Awk propose un jeu de fonctions et d'opérateurs que vous pouvez utiliser dans les sélecteurs ou les traitements:

fonctions
length(), substr(), int(), sqrt(), exp(), log(), …
opérateurs
, -, *, /, % , +, …

2 Les sélecteurs

On s'intéresse ici juste à la construction des sélecteurs. Pour cela, on utilise le traitement le plus simple que permet Awk, c'est-à-dire afficher toute la ligne correspondant à un sélecteur: print $0.

Exemple : La ligne de commande suivante permet d'exécuter un programme Awk très simple sur le résultat de la commande ls -l :

ls -l | awk '{ print $0 }'

Quel est le résultat de cette ligne de commande ? Comment écrire l'équivalent de la commande cat /etc/motd ?

2.1 Awk permet de construire 4 types de sélecteurs:

2.1.1 expression régulière :

il s'agit d'une expression qui définit un modèle de chaîne de caractères, comme par exemple:

  • les mots suite de caractères alphanumériques, c'est-à-dire ne contenant ni espace, ni tabulation, ni ponctuation, ni caractère spécial, …)
  • les mots commençant par la lettre 'a'
  • les mots de huit lettres ne contenant pas de chiffre
  • une suite d'au moins deux mots ne contenant pas de chiffre
  • un nombre de 2 ou 3 chiffres

2.1.2 expression de comparaison :

elle permet de comparer deux entités au moyen des opérateurs d'égalité/inégalité du langage C : + =, !, <, >, <=, >=. Ces entités peuvent être de deux types :

  • chaîne de caractères: chaîne littérale comme "abcdefg", les variables comme $0, $1, $2, … ou le résultat d'une fonction comme substr()
  • numérique: littéral comme 223, variable comme NF (qui indique le nombre de champs d'une ligne), ou le résultat d'une fonction comme length(), sqrt(), etc.

2.1.3 expression logique :

elle permet de combiner les deux types d'expressions précédentes avec des opérateurs logiques (||, &&, !) et des parenthèses.

2.1.4 expression d'intervalle :

elle permet de définir un ensemble de lignes comprises entre deux expressions des types précédents.

2.2 Exercices sur les expressions régulières:

Construisez et testez les sélecteurs qui permettent d’extraire du fichier http://runtime.bordeaux.inria.fr/furmento/bidouille/motd les lignes:

2.2.1 qui contiennent la lettre ’a’ ;

awk '/a/ { print $0 }' motd

2.2.2 qui contiennent au moins 2 fois la lettre ’a’ ;

awk '/a.*a/  { print $0 }' motd

2.2.3 qui contiennent le caractère '' (attention, rappelez-vous que '' est un caractère spécial de Awk…)

awk '/\*/ { print $0 }' motd

2.2.4 qui contiennent des successions de plus de 2 fois le caractère '' (c-à-d '*', '*', '**', …)

awk '/\*\*/ { print $0 }' motd

2.2.5 qui commencent et se terminent par le caractère '*'.

awk '/^\*.*\*$/ { print $0 }' motd

2.2.6 dans lesquelles le caractère '*' n’apparaît qu'en début et en fin de ligne

awk '/^\*[^*]*\*$/ { print $0 }' motd

Remarquez qu'entre les crochets, il n'est pas nécéssaire de déspécialiser le caractère '*'.

2.2.7 qui ne contiennent que le caractère '*'.

awk '/^\*+$/ { print $0 }' motd

2.2.8 qui contiennent des successions d'exactement trois fois le caractère '' (comme 'a***b', par exemple, mais ni 'a**b' ni 'a****b')

awk '/[^*]\*\*\*[^*]/ { print $0 }' motd

2.2.9 qui ne contiennent pas de chiffre.

awk '/^[^0-9]*$/ { print $0 }' motd

2.3 Exercices sur les expressions de comparison

Le fichier http://runtime.bordeaux.inria.fr/furmento/bidouille/dir.txt contient le résultat d'une commande ls-lg. Construisez et testez les sélecteurs qui permettent d'extraire de ce fichier les lignes correspondant aux fichiers:

2.3.1 dont le groupe est bin

awk '$4 == "bin" { print $0 }' dir.txt

2.3.2 dont la taille est ≥ 4 Mo

awk '$5 > 4*1024 { print $0 }' dir.txt

2.3.3 qui possèdent un nombre de liens ≥ 10

awk '$2 >= 10 { print $0 }' dir.txt

2.3.4 dont les permissions sont rwxr-xr-x

awk '$1 ~ "rwxr-xr-x" { print $0 }' dir.txt

remarquez que la commande ci-dessous ne fonctionne pas vu qu'elle teste l'égalité.

awk '$1 = "rwxr-xr-x" { print $0 }' dir.txt

2.3.5 dont le nom comporte plus de 10 caractères (fonction length)

awk 'length($9) > 10 { print $0 }' dir.txt

2.3.6 qui ont la permission r-x pour le propriétaire

awk '$1 ~ /^.r-x/ { print $0 }' dir.txt

2.3.7 qui ont la permission r-x pour le groupe

awk '$1 ~ /r-x...$/ { print $0 }' dir.txt

2.4 Exercices sur les expressions logiques

Le fichier http://runtime.bordeaux.inria.fr/furmento/bidouille/dir.txt contient le résultat d'une commande ls-lg. Construisez et testez les sélecteurs qui permettent d'extraire de ce fichier les lignes correspondant aux fichiers:

2.4.1 qui sont des répertoires et dont la taille est exactement 1024o ;

awk '$1 ~ /^d/ && $5 == 1024 { print $0 }' dir.txt

2.4.2 qui sont des répertoires mais pour lesquels la séquence de caractères 'sept' n'apparaît pas ;

awk '$1 ~ /^d/ && $0 !~ /sept/ { print $0}' dir.txt

2.4.3 qui ne sont pas des répertoires et dont l'heure de création est supérieure à midi

  • la fonction substr(chaîne,début,nombre) vous permet d'extraire de chaîne nombre caractères en partant du caractèe à la position début.
  • La négation peut s'exprimer de deux manières, soit dans l'expression régulière ($1 ne commence pas par la lettre 'd') soit dans l'expression logique (la négation de $1 commence par la lettre 'd').

    awk '$1 ~ /^[^d]/ && $8 ~ /:/ && substr($8,1,2) > 12 {print $0 }' dir.txt
    awk '! ($1 ~ /^d/) && $8 ~ /:/ && substr($8,1,2) > 12 {print $0 }' dir.txt
    

2.5 Exercices sur les expressions d'intervalle

Dans le fichier motd, recherchez les lignes comprises entre les instructions <DEBUT> et </DEBUT> (attention, le caractère '/' est un caractère spécial pour Awk !).

2.5.1 Solution

awk '/<DEBUT>/,/<\/DEBUT>/ { print $0 }' motd

3 Les traitements

3.1 Les instructions de contrôle

Awk propose les structures de contrôle du langage C comme par exemple:

  • if condition { instructions } else { instructions }
  • for( initialisation ; condition d'arrêt ; incrémentation }

3.2 Affichage

Awk propose deux fonctions pour afficher le résultat d'un traitement :

print [arg1 [arg2 …]
c'est la plus simple. Elle concatène les arguments qui lui sont passés en paramètre (de type chaîne ou numérique) et affiche la ligne correspondante.
printf(format,arg1,arg2,…)
équivalente à la fonction de même nom de C.

A partir du fichier dir.txt,

3.2.1 Afficher seulement le nombre de liens des fichiers

awk '{print $2}' dir.txt

3.2.2 Afficher seulement les champs qui concernent la date ou l'heure du fichier

awk '{print $6 " " $7 " " $8}' dir.txt
awk '{print $6,$7,$8}' dir.txt
awk '{OFS="---" ; print $6,$7,$8}' dir.txt

3.2.3 Précéder le nom des fichiers de leur taille affichée en Mo lorsque le fichier fait plus de 9999 Ko, ou de la taille normale sinon.

awk '$5 > 9999 {print int($5/1024) "M\t" $9}
     $5 <= 9999 {print $5 "\t" $9}' dir.txt
awk '{ if ($5 > 9999) print int($5/1024) "M\t" $9 ; else print $5 "\t" $9}' dir.txt

3.2.4 Afficher les champs de chacune des lignes dans l'ordre inverse.

awk '{j="" ; for(i=NF ; i>=1 ; i--) j=j$i"\t" ; print j}' dir.txt

3.3 Compteurs

Awk propose deux sélecteurs spéciaux, BEGIN et END, qui permettent de réaliser un traitement:

  • avant que la première ligne du/des fichier(s) inspecté(s) ne soit lue ;
  • après que la dernière ligne du/des fichier(s) inspectés ait été traitée.

Le premier, BEGIN, est généralement utilisé pour effectuer des initialisations (compteur, affichage d'un message de présentation, etc.), alors que le deuxième, END, est lui généralement utilisé pour réaliser des opérations qui ne sont possibles que lorsque toutes les lignes du fichier ont été parcourues (calcul et affichage de sommes, moyenne, etc.).

A partir du fichier dir.txt, faites calculer et afficher:

3.3.1 le nombre total de lignes parcourues

awk 'BEGIN {cpt=0}
     {cpt++}
     END {print "nombre de lignes : " cpt}' dir.txt
awk 'END {print "nombre de lignes : " NR}' dir.txt

3.3.2 la somme des tailles des fichiers

awk 'BEGIN {somme=0}
     {somme=somme+$5}
     END {print "somme des tailles : " somme}' dir.txt

3.3.3 la moyenne, le minimum et le maximum des tailles des fichiers

cat dir.txt | awk 'BEGIN {somme=0}
                   NR == 2 {min=$5 ; max=$5}
                   {somme=somme+$5 ;if ( $5 < min) min=$5 ; if ($5 > max) max=$5}
                   END {cpt=NR-1 ; print "moyenne=" (somme/cpt) " min=" min " max=" max}'

4 Et la suite

echo a b c d e f | awk 'BEGIN { RS = " " } NR>4 {print}'
echo a b c d e f | awk 'NR>4 {print}'
echo a b c d e f | awk '{print}'
echo a b c d e f | awk 'BEGIN { RS = " " } {print}'

Date: 07 novembre 2014

Author: Nathalie Furmento

Created: 2019-11-15 or. 17:35

Validate