AWK : Chercher et manipuler du texte mais pas que !
Table des matières
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:
-F<sep> : Sert à définir le séparateur de champ. Cette option est facultative.
On développera plus tard, c'est plus simple d'apprendre par l'exemple !
On développera plus tard, c'est plus simple d'apprendre par l'exemple !
J'aime bien l'apprentissage par l'exemple, allons-y progressivement !
Prenons par exemple la commande ps, elle me retourne ceci :
Si on souhaite n'afficher que la première colonne :
Le résultat sera :
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 :
Si vous voulez afficher plusieurs champs, plusieurs possibilités :
ou
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 :
Avec le deuxième exemple, on voit que le texte se met entre guillemets. Voici un exemple avec plus de texte :
On peut ajouter des conditions rapides, ici récupérons que les comptes utilisateurs (UID >= 1000 , champ 3) :
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 :
Si je ne veux filtrer que les lignes concernant mes volumes logiques (qui contiennent le mot mapper) :
Ici on affichera les colonnes 1 et 5.
Mais on peut afficher toute la ligne ! Cela se fait avec $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 :
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) :
Autre exemple avec ici, avec une condition sur le premier champ, et l'ajout d'une fonction int qui permet d'arrondir le calcul :
On peut utiliser plusieurs choses dans la fonction AWK, il suffit de séparer toutes les instructions avec des point virgules :
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 :
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 :
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 :
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 :
On peut utiliser la fonction substring pour ici, afficher à partir du 8ème caractère :
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 :
Pour afficher le nombre de lignes d'un fichier, on cherchera avec END :
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 :
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;}'