Manipules les champs et les lignes comme un boss avec la commande awk

commande awk

Libère le potentiel de ton terminal avec la commande AWK.

AWK est un formidable outil qui te permet de tordre à ta guise les outputs de ton terminal.

Je vais te donner les bases pour afficher et modifier les sorties de ton terminal.

Si je fais un simple ls -l voici le résultat :

ls -l
total 4
-rwxr-xr-x 1 babidi babidi 540 mars  26  2020 delete.sh
-rw-rw-r-- 1 babidi babidi   0 oct.  10 21:10 fichier_test
-rw-rw-r-- 1 babidi babidi   0 oct.  10 21:10 mot_start.sh
-rw-rw-r-- 1 babidi babidi   0 oct.  10 21:10 test

Affiche le champs souhaité du retour d’une commande: 

awk '{print $numéro de champs}' 

Exemple : 

Nous allons utiliser la commande ls –l et nous voulons n’afficher que le propriétaire du fichier et le nom de fichier : 

ls -l | awk '{print $3 " " $9}' 

  

babidi delete.sh 

babidi fichier_test 

babidi mot_start.sh 

babidi test 

Ici j’ai décidé d’afficher le 3eme champs puis un espace et enfin le champs 9.

$0toute la ligne
$1premier champ
$3 troisième champ
$12douzième champ

On peut donc afficher le champs que l’on veut dans l’ordre que l’on veut et ajouter des chaines de caractères n’importe où.

Utiliser le délimiteur de son choix

J’ai utilisé le délimiteur par défaut qui est la tabulation mais j’aurais également pu utiliser le délimiteur de mon choix avec l’argument FS=. Exemple: FS= »: » pour utiliser « : » comme délimiteur.

Si je prend le fichier passwd :

tail /etc/passwd
tcpdump:x:129:138::/nonexistent:/usr/sbin/nologin
nm-openvpn:x:130:141:NetworkManager OpenVPN,,,:/var/lib/openvpn/chroot:/usr/sbin/nologin
systemd-coredump:x:997:997:systemd Core Dumper:/:/usr/sbin/nologin
tss:x:131:142:TPM software stack,,,:/var/lib/tpm:/bin/false
_rpc:x:132:65534::/run/rpcbind:/usr/sbin/nologin
statd:x:133:65534::/var/lib/nfs:/usr/sbin/nologin
libvirt-qemu:x:64055:139:Libvirt Qemu,,,:/var/lib/libvirt:/usr/sbin/nologin
libvirt-dnsmasq:x:134:144:Libvirt Dnsmasq,,,:/var/lib/libvirt/dnsmasq:/usr/sbin/nologin
snapd-range-524288-root:x:524288:524288::/nonexistent:/bin/false
snap_daemon:x:584788:584788::/nonexistent:/bin/false

Si je souhaite afficher le premier et le troisième champ, je peux faire :

awk '{print $1" "$3}' FS=":" /etc/passwd

passwd
root 0
daemon 1
bin 2
sys 3
sync 4
games 5
man 6
lp 7
mail 8
news 9
uucp 10
proxy 13
www-data 33
...

Transformer l’output avec awk

Tu remarqueras que j’ai modifier la sortie avec les  » « .

Je peux totalement transformer le visuel de sortie à ma guise, exemple :

awk '{print "username:" $1 " uid:" $3}' FS=":" /etc/passwd
username:root uid:0
username:daemon uid:1
username:bin uid:2
username:sys uid:3
username:sync uid:4
username:games uid:5
username:man uid:6
username:lp uid:7
username:mail uid:8
username:news uid:9
username:uucp uid:10
username:proxy uid:13
username:www-data uid:33

Tu commences à comprendre la puissance de l’outil ? 😏

Afficher le nombre de ligne:

L’expression NR signifie le numéro de ligne, voici donc comment afficher le numéro de ligne :

ls -l | awk '{print "ligne " NR " " $0}' 

 

ligne 1 total 16 

ligne 2 -rwxr-xr-x 1 babidi babidi  540 mars  26 02:08 delete.sh 

ligne 3 -rw-r--r-- 1 babidi babidi  466 mai    6 20:03 fichier_test 

ligne 4 -rwxr-xr-x 1 babidi babidi  255 mai    6 20:28 mot_start.sh 

ligne 5 drwxr-xr-x 2 babidi babidi 4096 mars  26 02:08 test 

Remarque : la variable $0 dans la commande awk signifie l’intégralité de la ligne.

Afficher le nombre de champs:

ls -l | awk '{print "nombre de champs " NF " " $0}' 

nombre de champs 2 total 16 

nombre de champs 9 -rwxr-xr-x 1 babidi babidi  540 mars  26 02:08 delete.sh 

nombre de champs 9 -rw-r--r-- 1 babidi babidi  466 mai    6 20:03 fichier_test 

nombre de champs 9 -rwxr-xr-x 1 babidi babidi  255 mai    6 20:28 mot_start.sh 

nombre de champs 9 drwxr-xr-x 2 babidi babidi 4096 mars  26 02:08 test 

Là on demande d’afficher « nombre de champs » + NF qui correspond au numéro de champs + un espace  »  » + $0 qui afficher toute la ligne

Les conditions

Avec les conditions on peux extraire exactement ce qu’on veut.

Je veux extraire les lignes ou le premier champ est « postgres » :

awk '{ if($1 == "postgres") print "username:" $1 " uid:" $3}' FS=":" /etc/passwd

username:postgres uid:123

Pareil mais avec un else if :

awk '{ if($1 == "postgres") print "username:" $1 " uid:" $3; else if($1 == "mysql") print "username:" $1 " uid:" $3}' FS=":" /etc/passwd

username:postgres uid:123
username:mysql uid:127

On aurait pu faire pareil et plus court avec le or « || » :

awk '{ if($1 == "postgres" || $1 == "mysql") print "username:" $1 " uid:" $3}' FS=":" /etc/passwd

username:postgres uid:123
username:mysql uid:127

Une condition pour afficher les lignes ou le premier champs contient « oo » :

awk '$1 ~ /oo/ { print "username:" $1 " uid:" $3}' FS=":" /etc/passwd

username:root uid:0
username:whoopsie uid:109
username:kernoops uid:116
username:snapd-range-524288-root uid:524288

Si je souhaite afficher les lignes qui finissent en /bin/false :

awk '$7 ~ /bin\/false$/ { print "username:" $1 " uid:" $3}' FS=":" /etc/passwd
username:systemd-timesync uid:100
username:systemd-network uid:101
username:systemd-resolve uid:102
username:syslog uid:104
username:_apt uid:105
username:messagebus uid:106
username:uuidd uid:107
username:lightdm uid:108
username:whoopsie uid:109
username:avahi-autoipd uid:110
username:avahi uid:111
username:dnsmasq uid:112

$ correspond à la fin de la ligne.

Substitution d’une chaine de caractères: 

La commande gsub permet de subtituer une chaine de caractères par une autre sur les colonnes de notre souhait.

Exemple, utiliser la commande ls et substituer le nom d’utilisateur par un autre:

ls -l | awk '{gsub("babidi","BOSS",$0);print $0}' 


total 16 

-rwxr-xr-x 1 BOSS BOSS  540 mars  26 02:08 delete.sh 

-rw-r--r-- 1 BOSS BOSS  466 mai    6 20:03 fichier_test 

-rwxr-xr-x 1 BOSS BOSS  255 mai    6 20:28 mot_start.sh 

drwxr-xr-x 2 BOSS BOSS 4096 mars  26 02:08 test 

Calcul de statistique

awk '{somme+=$1} END {print somme}' nom_du_fichier

Ici on calcule la somme de la première colonne de chaque ligne et on affiche cette somme en fin de ligne.

Fusion de fichier

fusion awk linux
awk '{print}' fichier1.txt fichier2.txt > fichier_fusionne.txt

On fusionne fichier1.txt et fichier2.txt.

Il est aussi possible de rajouter des conditions pour récolter dans le fichier_fusionne.txt seulement les lignes intéressantes.

Tri

Par exemple si on veut trier les utiisateurs (fichier /etc/passwd) par leurs UID on peut utiliser la commande awk :

awk -F: '{print $1, $3}' /etc/passwd | sort -n -k2

En associant awk avec d’autres commande (ici sort) on peut facilement aller beaucoup plus loin dans l’affichage et l’organisation des données.

AWK et la boucle for

Il est possible d’afficher un fichier via une boucle for :

awk '{for (i=1; i<=NF; i++) {print $i}}' nom_du_fichier

Dans cette commande le nombre de champs est stocké dans la variable « NF ».

La boucle for parcourt les champs de 1 à NF et à chaque itération on affiche $i (chaque mot donc).

Si on rajoute des conditions on peux ajouter/modifier/supprimer des éléments à notre guise.

Exemples d’utilisations

  • Extraction de colonnes spécifiques d’un fichier
  • Sélection des lignes qui contiennent un mot spécifique
  • Calcul de statistiques sur les données
  • Formatage de données
  • Fusion de plusieurs fichiers
  • Sélection des lignes qui respectent une/des conditions
  • Substitution de caractères
  • Tri
  • Comptage de pattern

La doc complète de awk => https://www.gnu.org/software/gawk/manual/gawk.html

Besoin d’aide ?

Tu as besoin de conseil ou d’assistance pour un problème technique ou la conception d’un script, tu peux nous contacter ICI nous essayerons de t’apporter notre aide.

Si l’article t’a intéressé, n’hésites pas à le partager pour en faire profiter à tous.

⬇️

Laisser un commentaire