C.2. Awk

Awk est un langage de manipulation de texte plein de fonctionnalités avec une syntaxe proche du C. Alors qu'il possède un ensemble impressionnant d'opérateurs et de fonctionnalités, nous n'en couvrirons que quelques-uns, les plus utiles pour l'écriture de scripts shell.

Awk casse chaque ligne d'entrée en champs. Par défaut, un champ est une chaîne de caractères consécutifs délimités par des espaces, bien qu'il existe des options pour changer le délimiteur. Awk analyse et opère sur chaque champ. Ceci le rend idéal pour gérer des fichiers texte structurés, particulièrement des tableaux, des données organisées en ensembles cohérents tels que des lignes et des colonnes.

Desguillemets forts (guillemets simples) et des accolades entourent les segments de code awk dans un script shell.

# $1 est le premier champ, $2 est le second champ, etc.

echo un deux | awk '{print $1}'
# un

echo un deux | awk '{print $2}'
# deux

# Mais quel est le champ #0 ($0)?
echo un deux | awk '{print $0}'
# one two
# Tous les champs !


awk '{print $3}' $nomfichier
# Affiche le champ 3 du fichier $nomfichier sur stdout.

awk '{print $1 $5 $6}' $nomfichier
# Affiche les champs 1, 5 et 6 du fichier $nomfichier.

awk '{print $0}' $nomfichier
# Affiche le fichier entier the entire file!
# Même effet que :   cat $nomfichier . . . or . . . sed '' $nomfichier

Nous venons juste de voir la commande awk print en action. Les seules autres fonctionnalités de awk que nous avons besoin de gérer ici sont des variables. Awk gère les variables de façon similaire aux scripts shell, quoiqu'avec un peu plus de flexibilité.

{ total += ${numero_colonne} }

Ceci ajoute la valeur de numero_colonne au total total. Finalement, pour afficher « total », il existe un bloc de commandes END, exécuté après que le script ait opéré sur toute son entrée.

END { print total }

Correspondant au END, il existe BEGIN pour un bloc de code à exécuter avant que awk ne commence son travail sur son entrée.

L'exemple suivant illustre comment awk ajoute des outils d'analyse de texte dans un script shell.

Exemple C.1. Compteur sur le nombre d'occurences des lettres

#! /bin/sh
# letter-count2.sh : Compter les occurrences des lettres d'un fichier texte.
#
# Script de nyal [nyal@voila.fr].
# Utilisé dans le guide ABS avec sa permission.
# Nouveaux commentaires et reformatage par l'auteur du guide ABS.
# Version 1.1 : Modifié pour fonctionner avec gawk 3.1.3.
#               (Fonctionnera toujours avec les anciennes versions)


INIT_TAB_AWK=""
# Paramètre pour initialiser le script awk.
compteur=0
FICHIER_A_ANALYSER=$1

E_PARAMERR=65

usage()
{
    echo "Usage : letter-count.sh fichier lettres" 2>&1
    # Par exemple :   ./letter-count2.sh nom_fichier a b c
    exit $E_PARAMERR  # Pas assez d'arguments passés au script.
}

if [ ! -f "$1" ] ; then
    echo "$1 : Fichier inconnu." 2>&1
    usage      # Affiche le message d'usage et quitte.
fi 

if [ -z "$2" ] ; then
    echo "$2 : Aucune lettre spécifiée." 2>&1
    usage
fi 

shift                      # Lettres spécifiées.
for lettre in `echo $@`    # Pour chacune...
  do
  INIT_TAB_AWK="$INIT_TAB_AWK tableau_recherche[${compteur}] = \
  \"$lettre\"; tableau_final[${compteur}] = 0; "
  # A passer comme paramètres au script awk ci-dessous.
  compteur=`expr $compteur + 1`
done

# DEBUG :
# echo $INIT_TAB_AWK;

cat $FICHIER_A_ANALYSER |
# Envoyer le fichier cible au script awk suivant.

# --------------------------------------------------------------------------------------------------
# L'ancienne version du script utilisait
# awk -v tableau_recherche=0 -v tableau_final=0 -v tab=0 -v \
# nb_letter=0 -v chara=0 -v caractere2=0 \

awk \
"BEGIN { $INIT_TAB_AWK } \
{ split(\$0, tab, \"\"); \
for (caractere in tab) \
{ for (caractere2 in tableau_recherche) \
{ if (tableau_recherche[caractere2] == tab[caractere]) { tableau_final[caractere2]++ } } } } \
END { for (caractere in tableau_final) \
{ print tableau_recherche[caractere] \" => \" tableau_final[caractere] } }"
# --------------------------------------------------------------------------------
#  Rien de très compliqué, seulement...
#+ boucles for, tests if et quelques fonctions spécialisées.

exit $?

# Comparez ce script à letter-count.sh.

Pour des exemples simples de awk à l'intérieur de scripts shell, jetez un oeil sur :

  1. Exemple 14.13, « Forcer une déconnexion »

  2. Exemple 19.8, « Boucle for redirigée »

  3. Exemple 15.30, « Supprimer les commentaires des programmes C »

  4. Exemple 33.5, « Un script d'appel autour d'un autre script awk »

  5. Exemple 9.25, « Passer une référence indirecte à awk »

  6. Exemple 14.20, « Utiliser export pour passer une variable à un script awk embarqué »

  7. Exemple 27.2, « Trouver le processus associé à un PID »

  8. Exemple 27.3, « État de la connexion »

  9. Exemple 10.3, « Fileinfo : opérer sur une liste de fichiers contenue dans une variable »

  10. Exemple 15.57, « Effacer les fichiers de façon sûre »

  11. Exemple 9.31, « Réinitialiser RANDOM »

  12. Exemple 15.4, « Effacer un fichier par son numéro d'inode »

  13. Exemple 9.15, « Autres moyens d'extraire des sous-chaînes »

  14. Exemple 33.16, « Une astuce permettant de renvoyer plus d'une valeur de retour »

  15. Exemple 10.8, « Afficher tous les utilisateurs du système »

  16. Exemple 33.4, « Un script d'appel autour d'un script awk »

  17. Exemple 15.50, « Calculer l'hypoténuse d'un triangle »

C'est tout ce que nous allons voir sur awk mais il existe bien plus à apprendre. Voyez les références appropriées dans la Bibliographie.