Dernière modification : 24/08/2022

Commande AWK - Mémo

1. Présentation

"Awk est le plus souvent utilisé pour la production de fichiers textes aux spécifications particulières (échanges entre différents systèmes d'informations hétérogènes). Il est aussi utilisé comme analyseur (parser) de fichiers XML ou de fichiers textes pour générer des commandes SQL à partir des données extraites. Il peut être utilisé enfin pour des opérations de calculs complexes et mise en forme de données brutes pour faire des tableaux statistiques...

Il agit comme un filtre programmable prenant une série de lignes en entrée (sous forme de fichiers ou directement via l'entrée standard) et écrivant sur la sortie standard, qui peut être redirigée vers un autre fichier ou programme. Un programme Awk est composé de trois blocs distincts utilisables ou non pour le traitement d'un fichier (prétraitement, traitement, post-traitement). Awk lit l'entrée ligne par ligne, puis sélectionne (ou non) les lignes à traiter par des expressions rationnelles (et éventuellement des numéros de lignes). Une fois la ligne sélectionnée, elle est découpée en champs selon un séparateur d'entrée indiqué dans le programme awk par le symbole FS (qui par défaut correspond au caractère espace ou tabulation). Puis les différents champs sont disponibles dans des variables : $1 (premier champ), $2 (deuxième champ), $3 (troisième champ), …, $NF (dernier champ)." issue de  Wikipédia.

2. Syntaxe

La syntaxe est la suivante :

awk [options] [programme] [fichiers]

3. Les options

Ci-dessous la liste des options les plus populaires

-F séparateur Modification du séparateur de champs
-f fichier Lecture du programme à partir d'un fichier
-v awkVar=$shellVar Intégration des variables du shell dans le code awk

 

4. Le programme

Le programme peut avoir plusieurs structures, un mode inline et un mode plus structuré pour pouvoir réaliser des actions plus complexes de manière plus lisibles.

Mais avant toute chose, des variables spéciales peuvent être utilisées dans la partie programme. Voyons quelles sont-elles :

Les variables spéciales

Ces variables sont interprétées au lancement de awk.

Nom de la variable Valeur par défaut Rôle de la variable
RS Newline (\n) Record Separator : Caractère séparateur d'enregistrement (lignes).
FS Suite d'espaces et/ou de tabulations Field Separator : Caractères séparateurs de champs.
OFS Espace Output Field Separator : Séparateur de champ utilisé pour l'affichage.
ORS Newline (\n) Output Record Separator : Caractère séparateur d'enregistrement en sortie.
ARGV - Tableau initialisé contenant les arguments de la ligne de commande (options et nom du script awk exclus).
ARGC - Nombre d'éléments contenus dans le tableau ARGV.
ENVIRON Variables d'environnement exportées par le shell. Tableau contenant les variables d'environnement du shell.

 

Ci-dessous le tableau principal contenant la liste des principales variables.

Nom de la variable Valeur de la variable
$0 Valeur de l'enregistrement courant
NF Number of Field : Nombre de champs de l'enregistrement courant $0.
$1, $2, ... $NF $1 contient la valeur du 1er champ, $2 la valeur du 2ème champ etc ... et $NF la valeur du dernier champ.
NR Number : Indice de l'enregistrement courant (NR vaut 1 quand la 1ère ligne est en cours de traitement, puis s'incrémente dès que awk change d'enregistrement).
FNR File Number : Indice de l'enregistrement courant relatif au fichier en cours de traitement.
FILENAME Nom du fichier en cours de traitement.
RLENGTH Longueur de la chaîne de caractère trouvée par la fonction match()
RSTART Première position de la chaîne de caractère trouvée par la fonction match()

Remarque : On notera que les variables $1, $2 etc sont internes à awk et non au shell ici.

Exemple simple :

ps -aux | awk '{print $1,$11}'

Sortira automatiquement la première et la 11ème colonne issue de la commande ps.

ps -aux | awk '{print "Utilisateur : " , $1, "\tCommande : " , $11}'

Sortira automatiquement la première et la 11ème colonne issue de la commande ps formatée.

L'exemple suivant utilise l'option "-F" qui permet de définir le délimiteur, ici ":" :

cat /etc/passwd | awk -F : '{print $1,$6}'

On a vu précédemment que $0 affichait la ligne entièrement. si on laisse print sans aucun argument, alors la ligne sera affichée entièrement également :

cat /etc/passwd | awk -F : '{print}'

Cet exemple affichera toute les lignes du fichier sans distinction.

5. Les filtres et les tests logiques

Il est possible de filtrer avec awk. Le critère peut être une expression d'opérateurs et renvoyant la valeur vrai ou faux.

Ci-dessous les opérateurs de tests courants :

Opérateur Signification
< Inférieur
> Supérieur
<= Inférieur ou égal
>= Supérieur ou égal
== Test d'égalité
!= Test d'inégalité
~ Correspondance avec une expression régulière
!~ Non-correspondance avec une expression régulière
! Négation
&& Et logique
|| Ou logique
(expression) Regroupement

 

Quelques exemples :

# Aucun filtre mais affiche tout le fichier
awk '/MOTIF/ {print}' fic.txt

# Aucun filtre mais affiche tout le fichier
awk -F':' '/MOTIF/ {print}' fic.txt

# Afficher uniquement les lignes dont le 6eme champ commence par MOTIF
$ awk -F':' '$6 ~ /^MOTIF/ {print}' fic.txt

# Afficher uniquement les lignes dont le 6eme champ NE commence PAS par MOTIF
$ awk -F':' '$6 !~ /^MOTIF/ {print}' fic.txt

# Afficher uniquement les lignes paires
awk -F':' 'NR%2==0 {print $0}' fic.txt

# Afficher les champs 1 et 4 des lignes 4 et 8 du fichier fic.txt
$ awk -F':' 'NR == 4 || NR == 8 {print $1,":",$4}' fic.txt

# Afficher les champs 1 et 7 des lignes 4 à 8 du fichier fic.txt
awk -F':' 'NR == 4 , NR == 8 {print $1,"==>",$7}' fic.txt

# Afficher les champs en ordre inverse
echo "a b c d e f" | awk '{for (i=NF; i>0; i--) {printf("%s ",$i)}}'

# Afficher les champs en ordre inverse en ajoutant un saut de ligne à fin
echo "a b c d e f" | awk '{for (i=NF; i>0; i--) {printf("%s ",$i)} printf "\n"}'

# Utilisation de variable
var="hello"
awk -v x="$var" 'BEGIN {print x}'
# Output : hello

 

Autres exemples utiles (Wikipédia) :

awk '{print $0}' fichier : affiche toutes les lignes de fichier (idem que cat fichier).

awk '/2/ {print $0}' fichier : affiche toutes les lignes où le caractère 2 est présent (idem que grep '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 du fichier, mais chaque ligne est précédée de son numéro.

awk -F: '{print $1}' /etc/passwd : renvoie la liste des utilisateurs (idem cut -d : -f 1 /etc/passwd).

awk '/Motif1/ , /Motif2/' fichier : écrit toutes les lignes contenues dans le fichier entre le Motif1 et le Motif2.

 

6. Le mode structuré

Il est possible pour des usages plus complexes d’utiliser awk de manière plus structuré via les mots clés BEGIN et END.

$ cat fichier.awk
BEGIN {
    print "Démarrage du programme"
}
{
    print "Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement"
}
END {
    print "Fin du programme"
}

Pour exécuter ce script, exécuter la commande suivante :

awk -f fichier.awk /etc/passwd

Vous verrez alors ceci :

Démarrage du programme
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
......
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Pas de critères. Donc ce message s'affiche autant de fois qu'il y a d'enregistrement
Fin du programme

On peut changer le script de la manière suivante :

BEGIN {
    print "Analyse du fichier /etc/passwd"
    FS=":" # Changement du séparateur de champ
}
{
    print "User : " $1
    print "Home : " $6
    print ""
}
END {
    print "Fin d'analyse du fichier /etc/passwd"
}

Pour exécuter ce script, exécuter la commande suivante :

awk -f fichier.awk /etc/passwd

Vous verrez alors ceci :

User : root
Home : /root

User : daemon
Home : /usr/sbin

User : bin
Home : /bin

User : sys
Home : /dev

User : sync
Home : /bin

User : games
Home : /usr/games

 

Il est possible de rajouter des conditions et d'afficher le résultat via la fonction print. Un exemple issue du site https://www.quennec.fr/book/export/html/429 .

$ cat infoproc.awk
BEGIN{
	RS="\n\n"	# Separateur d'enregistrement
	FS="\n"		# Separateur de ligne
	# En-tete et debut de page HTML
	print "<html>"
	print "<head>"
	print "<title>Informations CPU et m&eacute;moire</title>"
	print "<style type=\"text/css\">"
	print "table {border: solid thin; padding 10px; margin 5px}"
	print "table.proc {color: DarkSlateBlue; border-color: DarkSlateBlue}"
	print "table.proc caption {color: white; background: DarkSlateBlue; text-align: center}"
	print "table.mem {color: DarkGreen; border-color: DarkGreen}"
	print "table.mem caption {color: white; background: DarkGreen; text-align: center}"
	print "</style>"
	print "</head>"
	print "<body>"
	print "<table><tr>"
}
FILENAME ~ /cpuinfo$/ { print "<td valign=\"top\"><table class=\"proc\">"}
FILENAME ~ /meminfo$/ { print "<td valign=\"top\"><table class=\"mem\">"}
{
	for(i=1; i<=NF; i++){
		split($i, cpu, ":")
		if(i==1) print "<caption>", cpu[1], cpu[2], "</caption>"
		else print "<tr><td>", cpu[1], "</td><td>", cpu[2], "</td></tr>"
	}
	print "</table></td>"
}
END{
	# Fin de page HTML
	print "</tr></table>"
	print "</body>"
	print "</html>"
}

A exécuter via la commande suivante :

awk -f infoproc.awk /proc/cpuinfo /proc/meminfo > infoproc.html

Cet exemple regroupe les boucles for, les conditions, l'utilisation de print et les variables possibles.

Pour ce dernier exemple, on regroupe toutes les lignes pour les utiliser dans les $i. Puis ou découpe manuellement la vrai ligne en question pour correspondre à ce que l'on attend. Par conséquent, il ne passera qu'une seule fois par fichier dans le corps du awk.

 

Fonctions utiles :

  • getline : https://www.gnu.org/software/gawk/manual/html_node/Getline.html
  • next : https://www.gnu.org/software/gawk/manual/html_node/Next-Statement.html
  • printf : https://www.gnu.org/software/gawk/manual/html_node/Printf.html

 

Sources de l'article :

  • https://linux.die.net/man/1/awk
  • https://fr.wikipedia.org/wiki/Awk
  • https://www.quennec.fr/
  • http://www.sysop.fr/
  • https://www.gnu.org/
  • Internet en général

LauLem.com - Conditions Générales d'Utilisation - Informations Légales - Charte relative aux cookies - Charte sur la protection des données personnelles - A propos