Commandes de base

AWK : Chercher et manipuler du texte mais pas que !

Cet article a été mis à jour, vous consultez ici une archive de cet article!
Table des matières

Présentation



Définition



AWK est utilisé pour la manipulation de fichiers textuels pour des opérations de recherches, de remplacement et de transformations complexes.

awk s'utilise de cette façon:
Code BASH :
awk -options {instructions}  fichier 


Les options



-F<sep> : Sert à définir le séparateur de champ. Cette option est facultative.

Les variables



On développera plus tard, c'est plus simple d'apprendre par l'exemple !

Les fonctions



On développera plus tard, c'est plus simple d'apprendre par l'exemple !

Exemples



J'aime bien l'apprentissage par l'exemple, allons-y progressivement !

Prenons par exemple la commande ps, elle me retourne ceci :

Code BASH :
  PID TTY          TIME CMD
21142 pts/0    00:00:00 bash
21270 pts/0    00:00:00 ps


Si on souhaite n'afficher que la première colonne :

Code BASH :
ps | awk '{print $1}'


Le résultat sera :

Code TEXT :
PID
21142
21555
21556


Par défaut c'est l'espace/tabulation le séparateur de champ. On pourra le modifier avec -F.
Exemple avec le fichier /etc/passwd qui contient la liste des utilisateurs, leur shell, leur dossier personnel. Pour récupérer la première colone :

Code BASH :
awk -F ":" '{ print $1}' /etc/passwd


Si vous voulez afficher plusieurs champs, plusieurs possibilités :
Code BASH :
awk -F ":" '{ print $1, $7}' /etc/passwd

ou
Code BASH :
awk -F ":" '{ print $1" "$7}' /etc/passwd


Avec le premier exemple, vous constatez que le séparateur de sortie (pour l'affichage) c'est l'espace. On peut le redéfinir avec OFS ainsi :
Code BASH :
awk 'BEGIN{FS=":"; OFS="\t"} { print $1,$7}' /etc/passwd


Avec le deuxième exemple, on voit que le texte se met entre guillemets. Voici un exemple avec plus de texte :
Code BASH :
awk -F ":" '{ print "Login : "$1"\t Shell : "$7}' /etc/passwd


On peut ajouter des conditions rapides, ici récupérons que les comptes utilisateurs (UID >= 1000 , champ 3) :
Code BASH :
awk -F ":" '$3 >= 1000 {print "Login : " $1"\t UID : "$3}' /etc/passwd



Pour effectuer une recherche dans un fichier ou une sortie de commande, on pourra utiliser le motif de recherche entre deux barres obliques :

Exemple, la sortie de la commande df sur ma machine :

Code TEXT :
Sys. de fichiers         blocs de 1K    Utilisé Disponible Uti% Monté sur
devtmpfs                       10240          0      10240   0% /dev
shm                          8204460     545788    7658672   7% /dev/shm
tmpfs                        8204460       1624    8202836   1% /run
/dev/mapper/rootvg-root     66956728   39494728   27131044  60% /
cgroup_root                    10240          0      10240   0% /sys/fs/cgroup
/dev/sda2                    1011144     187806     808767  19% /boot
/dev/sda1                     100808        249     100560   1% /boot/efi
/dev/mapper/rootvg-home    143972492  102341848   40460828  72% /home
/dev/sdb1                 1921811248 1713668144  188591588  91% /media/DATA
/dev/mapper/rootvg-vmssd    87468064   21141316   66257936  25% /media/SSD
tmpfs                        1640892         28    1640864   1% /run/user/1000


Si je ne veux filtrer que les lignes concernant mes volumes logiques (qui contiennent le mot mapper) :

Code BASH :
df | awk '/mapper/ {print $1"\t"$5}'


Ici on affichera les colonnes 1 et 5.

Mais on peut afficher toute la ligne ! Cela se fait avec $0 :
Code BASH :
df | awk '/mapper/ {print $0}'


On peut cumuler des filtres et des filtres inverses avec la négation, symbole point d'exclamation. Ici filtre avec les lignes mapper qui ne contiennent pas vm :
Code BASH :
df | awk '/mapper/ && !/vm/ {print $0}'


On peut aussi faire des calculs, ici, j'affiche la colonne 1 et la somme de la 3ème et la 4ème (dans df c'est le Utilisé et le Disponible, donc ça nous génère la taille totale du volume) :
Code BASH :
df | awk '/mapper/ {print $1"\t"$3+$4}'


Autre exemple avec ici, avec une condition sur le premier champ, et l'ajout d'une fonction int qui permet d'arrondir le calcul :
Code BASH :
free -m | awk '{ if($1 == "Mem:") print int($3/$2*100) "%"; }'


On peut utiliser plusieurs choses dans la fonction AWK, il suffit de séparer toutes les instructions avec des point virgules :
Code BASH :
awk '{ if ($1=="0")  print "ROUTEUR OFF" ; if ($1=="1") print "ROUTEUR ON"  }' /proc/sys/net/ipv4/ip_forward


On va prendre d'autres exemples sur le fichier /etc/shells qui contient la liste des shell dispo sur la machine.

On va afficher le nom du shell. Le but est donc de filtrer les lignes commençant par /, d'utiliser ce séparateur / et d'afficher le dernier champ.
NF correspondant au nombre de champs, s'il y en a 3, $NF vaudra donc $3 :

Code BASH :
awk -F "/" '/^\// {print $NF}'  /etc/shells 

Remarquez l'échappement du slash avec un anti-slash !

Il existe une fonction qui permet de calculer une longueur de chaîne. Ici on va afficher les lignes de plus de 8 caractères :
Code BASH :
awk 'length($0) > 8' /etc/shells


Repartons avec la commande ps.
On va afficher les lignes dont le dernier champ est /bin/bash, mixons donc conditions et NF vu précédemment :
Code BASH :
ps -ef | awk '{ if($NF == "/bin/bash") print $0}'


Avec les conditions, on peut utiliser les match et les expressions régulières :
Exemple : Afficher toutes les lignes de notre config kernel commençant par CONFIG :
Code BASH :
awk '$1 ~ /^CONFIG/ {print $0}' /boot/config-5.4.80-gentoo-r1-adrien


On peut utiliser la fonction substring pour ici, afficher à partir du 8ème caractère :
Code BASH :
awk '$1 ~ /^CONFIG/ {print substr($0,8) }' /boot/config-5.4.80-gentoo-r1-adrien


Le match peut aussi se faire avec la fonction match. Ça nous permet d’utiliser RSTART qui nous indique la position du premier caractère qui match avec l'expression de la fonction match :
awk 'match($0, /EXT4/) { print $0 " a la chaine EXT4 à la position " RSTART}' /boot/config-5.4.80-gentoo-r1-adrien

On a aussi NR pour Number Record. On pourra l'utiliser ainsi, pour n'afficher que les 6 premières lignes :
Code BASH :
df | awk 'NR<6 {print NR, $0}'


Pour afficher le nombre de lignes d'un fichier, on cherchera avec END :
Code BASH :
awk 'END { print NR}' /etc/passwd


Ah ouais et un truc marrant, on peut scripter avec des fonctions basiques.
Voici un exemple qui ne sert à rien, mais qui vous illustre les possibilités :
Code BASH :
awk 'BEGIN { for(i=1; i<=10; i++) print "Le carré de ", i, " est ", i*i;}'