C.2. Awk

Awk [140] est un langage de manipulation de textes riche de fonctionnalités, dont la syntaxe est 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 découpe 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 d'occurences des lettres

#! /bin/sh
# letter-count2.sh: Counting letter occurrences in a text file.
#
# Script by nyal [nyal@voila.fr].
# Used in ABS Guide with permission.
# Recommented and reformatted by ABS Guide author.
# Version 1.1: Modified to work with gawk 3.1.3.
#              (Will still work with earlier versions.)


INIT_TAB_AWK=""
# Parameter to initialize awk script.
count_case=0
FILE_PARSE=$1

E_PARAMERR=85

usage()
{
    echo "Usage: letter-count.sh file letters" 2>&1
    # For example:   ./letter-count2.sh filename.txt a b c
    exit $E_PARAMERR  # Too few arguments passed to script.
}

if [ ! -f "$1" ] ; then
    echo "$1: No such file." 2>&1
    usage                 # Print usage message and exit.
fi 

if [ -z "$2" ] ; then
    echo "$2: No letters specified." 2>&1
    usage
fi 

shift                      # Letters specified.
for letter in `echo $@`    # For each one . . .
  do
  INIT_TAB_AWK="$INIT_TAB_AWK tab_search[${count_case}] = \
  \"$letter\"; final_tab[${count_case}] = 0; " 
  # Pass as parameter to awk script below.
  count_case=`expr $count_case + 1`
done

# DEBUG:
# echo $INIT_TAB_AWK;

cat $FILE_PARSE |
# Pipe the target file to the following awk script.

# ---------------------------------------------------------------------
# Earlier version of script:
# awk -v tab_search=0 -v final_tab=0 -v tab=0 -v \
# nb_letter=0 -v chara=0 -v chara2=0 \

awk \
"BEGIN { $INIT_TAB_AWK } \
{ split(\$0, tab, \"\"); \
for (chara in tab) \
{ for (chara2 in tab_search) \
{ if (tab_search[chara2] == tab[chara]) { final_tab[chara2]++ } } } } \
END { for (chara in final_tab) \
{ print tab_search[chara] \" => \" final_tab[chara] } }"
# ---------------------------------------------------------------------
#  Nothing all that complicated, just . . .
#+ for-loops, if-tests, and a couple of specialized functions.

exit $?

# Compare this script to letter-count.sh.

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

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

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

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

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

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

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

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

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

  9. Exemple 11.3, « Fileinfo : opérer sur une variable contenant une liste de fichiers »

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

  11. Exemple 9.16, « Réinitialiser RANDOM »

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

  13. Exemple 10.6, « Autres moyens pour extraire ou situer des sous-chaînes »

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

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

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

  17. Exemple 16.53, « 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.



[140] Le nom de « Awk » vient des initiales des auteurs du langage : Aho, Weinberg, et Kernighan.