1. Opérations sur les fichiers et filtres

La plupart du travail en ligne de commande s'applique à des fichiers. Dans cette section nous vous montrerons comment surveiller et filtrer l'information dans les fichiers, extraire des informations spécifiques avec une simple commande, et trier le contenu des fichiers.

1.1. cat, tail, head, tee : afficher des fichiers

Ces commandes ont pratiquement toutes la même syntaxe : commande [option(s)] [fichier(s)], et peuvent être utilisées dans un tube. Elles sont toutes utilisées pour imprimer une partie d'un fichier selon certains critères.

L'utilitaire cat agglomère des fichiers et les imprime sur la sortie standard, qui est généralement l'écran de votre ordinateur. C'est une des commandes les plus utilisées. Vous pouvez utiliser :

# cat /var/log/mail/info

pour afficher, par exemple, le contenu du journal (log) du démon de courrier sur la sortie standard[26]. la commande cat a une option très utile (-n) qui permet de numéroter les lignes affichées.

Certains fichiers, comme les fichiers journaux des démons (s'ils sont en exécution), sont souvent de taille énorme[27] et les afficher dans leur intégralité à l'écran n'a aucun intérêt. Vous voudrez souvent ne consulter que quelques lignes d'un fichier. Pour ce faire, vous pouvez utiliser la commande tail. Par défaut, elle affichera les dix dernières lignes du fichier /var/log/mail/info :

# tail /var/log/mail/info

Les fichiers comme les journaux changent souvent de façon dynamique car le démon associé à ce fichier journal rajoute constamment de l'information au sujet de son activité. Si vous voulez alors surveiller de manière interactive des changements sur ces journaux, vous pouvez tirer avantage de l'option -f :

# tail -f /var/log/mail/info

Dans ce cas, tous les changements dans le fichier /var/log/mail/info sont affichés immédiatement à l'écran. L'utilisation de cette option est très utile lorsque vous voulez mieux comprendre comment fonctionne votre système. Par exemple, en regardant dans le journal /var/log/messages, vous pouvez surveiller les messages du système et plusieurs démons.

Si vous utilisez tail avec plus d'un fichier à la fois, le nom de chaque fichier sera affiché au dessus du contenu de ce dernier. Ceci est aussi valable lorsque vous profitez de l'option -f, en plus d'être utile pour observer les différentes interactions du système.

Vous pouvez utiliser l'option -n pour afficher les dernières lignes d'un fichier. Par exemple, si vous souhaitez n'afficher que les deux dernières lignes, vous exécuterez :

# tail -n2 /var/log/mail/info

Comme pour n'importe quelle autre commande, vous pouvez entrer plusieurs options en même temps. Par exemple, si vous combinez -n2 et -f, les deux dernières lignes du fichier s'afficheront ainsi que toutes celles qui s'inscriront en temps réel.

La commande head est similaire à tail, mais elle affiche les premières lignes d'un fichier. La commande qui suit imprimera à l'écran, par défaut, les 10 premières lignes du fichier /var/log/mail/info :

# head /var/log/mail/info

Comme avec tail, vous pouvez utiliser l'option -n pour spécifier le nombre de lignes à afficher à l'écran. Par exemple, pour afficher les deux premières lignes :

# head -n2 /var/log/mail/info

Vous pouvez aussi utiliser ces commandes de concert. Par exemple, si vous souhaitez seulement afficher les lignes 9 et 10, vous pouvez lancer la commande head qui sélectionnera les 10 premières lignes du fichier, les passera à la commande tail au travers d'un tube (|) :

# head /var/log/mail/info | tail -n2

La dernière partie de la commande sélectionnera les 2 dernières lignes et les imprimera à l'écran. De la même façon vous pouvez sélectionner la ligne 20 en comptant à partir de la fin du fichier :

# tail -n20 /var/log/mail/info |head -n1

Dans cet exemple, nous disons à tail de sélectionner les 20 dernières lignes du fichier, puis de les passer à head. Cette dernière en affiche alors la première ligne.

Supposons maintenant que nous souhaitions à la fois afficher à l'écran et enregistrer le résultat de la commande précédente dans le fichier resultats.txt. L'utilitaire tee va nous y aider. Sa syntaxe est :

tee [option(s)] [file]

Nous changeons alors la commande précédente :

# tail -n20 /var/log/mail/info |head -n1|tee resultats.txt

Prenons un autre exemple. Nous voulons sélectionner les 20 dernières lignes, les enregistrer dans resultats.txt, mais afficher à l'écran seulement les premières de ces lignes. Nous écrivons alors :

# tail -n20 /var/log/mail/info |tee resultats.txt |head -n1

La commande tee a une option très utile (-a) qui permet d'ajouter des données à un fichier existant.

Dans la section qui suit nous verrons comment utiliser grep comme filtre pour séparer les messages de Postfix des messages émanant d'autres services.

1.2. grep : rechercher du texte dans un ou plusieurs fichier(s)

Ni son nom ni son acronyme ne sont intuitifs (General Regular Expression Parser) mais son utilisation est très simple : il cherche un motif donné en argument dans un ou plusieurs fichiers. Sa syntaxe est :

grep [options] <motif> [un ou
 plusieurs fichier(s)]

Si vous avez précisé plusieurs fichiers, leurs noms apparaîtront en début de ligne. Vous pouvez utiliser l'option -h pour que les noms de fichiers n'apparaissent pas ou l'option -l, pour obtenir l'effet inverse, à savoir n'afficher que le nom des fichiers qui remplissent les conditions du motif. Le motif est une expression régulière, bien que la plupart du temps, il ne consiste qu'en un simple mot. Les options les plus couramment utilisées sont les suivantes :

  • -i : rechercher en ignorant la casse (c'est-à-dire ignorer la différence entre majuscules et minuscules).

  • -v : inverser la recherche, donc trouver les lignes ne correspondant pas au motif.

  • -n : afficher le numéro de ligne pour chaque ligne trouvée.

  • -w : dit à grep que le motif doit correspondre à un mot entier. Attention, les caractères considérés comme pouvant faire partie d'un mot dépendent du réglage de la langue.

Reprenons notre exemple du fichier journal du démon de courrier. Nous souhaitons trouver toutes les lignes du fichier /var/log/mail/info qui contiennent le motif postfix. Entrons alors la commande suivante :

# grep postfix /var/log/mail/info

Si nous voulons trouver toutes les lignes qui ne contiennent PAS la séquence « postfix », nous utilisons l'option -v :

# grep -v postfix /var/log/mail/info

La commande grep peut être utilisée dans un tube.

Supposons que nous voulions trouver tous les messages signalant un courrier envoyé avec succès. Dans ce cas, nous devons filtrer les lignes du journal provenant du démon de courrier (contenant donc la séquence « postfix ») contenant la séquence indiquant un envoi réussi (« status=sent ») [28] :

# grep postfix /var/log/mail/info |grep status=sent

Dans ce cas, grep est utilisé deux fois. C'est possible mais pas très élégant. Nous pouvons obtenir le même résultat en utilisant l'utilitaire fgrep. fgrep est en fait une méthode plus simple que d'entrer grep -F. Pour cela nous devons créer le fichier sequences.txt contenant les séquences écrites sur une colonne (une séquence par ligne). Un tel fichier peut être obtenu de cette façon :

# echo -e 'status=sent\npostfix' >./sequences.txt

Vérifiez le résultat avec la commande cat. \n est un motif spécial qui signifie « nouvelle ligne ».

Nous appelons alors une commande utilisant le fichier de séquences sequences.txt et l'utilitaire fgrep au lieu du « double appel » à grep :

# fgrep -f ./sequences.txt /var/log/mail/info

Le fichier ./sequences.txt peut contenir autant de séquences de filtrage que vous le souhaitez. Par exemple, pour sélectionner les messages correctement envoyés à pierre@mandriva.com, il suffira de rajouter cette adresse dans notre fichier ./sequences.txt en lançant cette commande :

# echo pierre@mandriva.com' >>./sequences.txt

Il est évident que vous pouvez combiner grep avec tail et head. Si nous souhaitons trouver l'avant-dernier message envoyé à pierre@mandriva.com, nous tapons :

# fgrep -f ./sequences.txt /var/log/mail/info | tail -n2 | head -n1

Nous appliquons ici le filtre construit précédemment et dirigeons le résultat dans un tube pour les commandes tail et head. Elles se chargent de sélectionner toutes les lignes de données à l'exception de la dernière.

1.3. Expressions régulières et filtrage egrep

Avec grep, nous sommes obliger de n'utiliser que des séquences ou des données précises. Comment trouver alors tous les courriers électroniques envoyés à chacun des employés de la « Société ABC » ? Afficher tous leurs messages n'est pas une tâche facile, de plus nous risquerions d'oublier quelqu'un ou de devoir chercher les messages un à un dans le journal.

Comme pour fgrep, egrep est en fait un raccourci de la commande grep -E. Il utilise les expressions régulières plutôt que les séquences, ce qui le rend beaucoup plus puissant pour traiter du texte.

Voici quelques expressions régulières en plus de celles que nous avions déjà mentionnées dans la section Section 3, « Motifs d'englobement du shell », lorsque nous évoquions les caractères d'englobement (globbing patterns) :

  • [:alnum:] (toutes les lettres et tous les nombres), [:alpha:] (toutes les lettres majuscules et minuscules) et [:digit:] (tous les nombres) peuvent être utilisés au lieu de définir vous-même les classes de caractères. De plus, ils intègrent les caractères internationaux (tels que les lettres accentuées, par exemple) et respectent la langue employée par le système.

  • [:print:] représente tous les caractères qui peuvent être affichés à l'écran.

  • [:lower:] et [:upper:] incarnent toutes les lettres minuscules et majuscules.

D'autres classes existent et vous pouvez toutes les retrouver dans la partie egrep(1). Celles citées plus haut sont les plus couramment utilisées.

Une expression régulière peut être suivie par un des nombreux opérateurs de répétition suivants :

?

L'item précédent est optionnel, c'est-à-dire qu'il peut se produire aucune fois ou une fois, mais plus plus d'une fois.

*

autant d'occurrences que possible pour l'entité précédente.

+

Au moins une occurrence.

{n}

Exactement n occurrences.

{n,}

Au moins n occurrences.

{n,m}

Au moins n occurrences, mais au plus m.

Si vous insérez une expression régulière entre parenthèses, vous pourrez réutiliser l'occurrence correspondante par la suite. Imaginons que vous ayez utilisé l'expression [:alpha:]+, qui peut représenter un mot. Si vous souhaitez repérer les mots qui sont utilisés deux fois, vous pouvez mettre cette expression entre parenthèses et la réutiliser avec le code \1 dans le premier groupe. Il est possible d'utiliser jusqu'à 9 de ces « mémoires ».

$ echo -e "abc def\nabc abc def\nabc1 abc1\nabcdef\nabcdabcd\nabcdef abcef" > fichiertest
$ egrep "([[:alpha:]]+) \1" fichiertest
abc abc def
$
[Note]Note

Les caractères [ et ] font partie du nom du groupe, nous devons donc les inclure pour utiliser cette classe de caractères. Le premier [ indique que nous commençons un groupe de caractères, le second fait partie du nom du groupe, puis viennent les caractères ] fermant correspondants.

L'unique ligne retournée est celle contenant deux groupes de lettres successifs séparés par un espace. Aucun autre groupe ne correspond à l'expression régulière.

Vous pouvez aussi utiliser le caractère | pour faire correspondre soit l'expression à gauche du | soit l'expression à sa droite. C'est un opérateur qui joint les deux expression. En utilisant le même fichiertest créé ci-dessus, vous pouvez rechercher les expressions qui contiennent des mots doubles, ou qui contiennent des mots doubles contenant des chiffres :

$ egrep "([[:alpha:]]+) \1|([[:alpha:][:digit:]]+) \2" fichiertest
abc abc def
abc1 abc1
$

Notez que pour le deuxième groupe utilisant les parenthèses, nous avons utilisé le code \2. Une expression plus efficace aurait été dans notre cas :

$ egrep "([[:alnum:]]+) \1" fichiertest
abc abc def
abc1 abc1
$

Finalement; pour tester la présence de certains caractères, vous devez les « échapper », en les faisant précéder d'une barre oblique inverse (backslash). Ces caractères sont : ?, +, {, |, (, ) et bien sûr \. Pour obtenir ces caractères vous devez donc utiliser : \?, \+, \{, \|, \(, \) et \\.

Ce petit exemple peut même vous être utile pour repérer les répétitions dans « vos » textes.

Les expressions régulières devraient suivre ces quelques règles, sur tous les outils qui les utilisent, à quelques nuances près. Prendre un peu de temps pour comprendre ces règles vous aidera beaucoup lorsque vous les utiliserez avec d'autres outils tels que sed. sed permet de manipuler du texte, notamment effectuer des modifications en utilisant des expressions régulières.

1.4. wc : compter des éléments de fichier

La commande wc (Word Count ou « compteur de mots ») sert à compter le nombre de lignes, de mots et de chaînes de caractère et de mots dans un fichier. Elle sert aussi à calculer la longueur de la ligne la plus longue. Sa syntaxe est :

wc [option(s)] [fichier(s)]

Les options suivantes sont particulièrement utiles :

  • -l: affiche le nombre de lignes ;

  • -w: affiche le nombre de mots ;

  • -m: affiche le nombre total de caractères;

  • -c: affiche le nombre total d'octets ;

  • -L: affiche la longueur de la plus longue ligne du texte.

la commande wc affiche par défaut le nombre de lignes, mots et caractères du fichier fourni. Voici quelques exemples :

Si nous souhaitons connaître le nombre d'utilisateurs sur notre système, nous pouvons taper :

$wc -l /etc/passwd 

Si nous souhaitons connaître le nombre de processeurs sur notre système :

$grep "model name" /proc/cpuinfo |wc -l

Dans la section précédente, nous avons obtenu une liste de messages correspondant aux séquences du fichier ./sequences.txt. Si nous souhaitons connaître le nombre de ces messages, nous pouvons rediriger les résultats de notre filtre dans un tube pour la commande wc :

# fgrep -f ./sequences.txt /var/log/mail/info | wc -l

1.5. sort: Trier le contenu de fichiers

Voici la syntaxe de cet utilitaire de tri très puissant[29]:

sort [option(s)] [fichier(s)]

Considérons le tri du fichier /etc/passwd. Comme vous pouvez le voir :

$ cat /etc/passwd

Nous voulons le trier par champ login (nom d'utilisateur) :

$ sort /etc/passwd

La commande sort trie les données par ordre croissant sur le premier champ (dans notre cas, le champ login) par défaut. Pour trier les données par ordre décroissant, utilisez l'option -r :

$ sort -r /etc/passwd

Chaque utilisateur a son propre UID (identifiant numérique de l'utilisateur) écrit dans le fichier /etc/passwd. Trions donc les utilisateurs selon leur UID :

$ sort /etc/passwd -t":" -k3 -n

Nous avons utilisé ici les options suivantes de sort :

  • -t":": indique à sort que le séparateur de champs est le symbole ":" ;

  • -k3: indique que le tri doit s'effectuer sur la troisième colonne ;

  • -n: indique que le tri doit s'effectuer sur des données numériques et non pas alphabétiques.

Et par ordre décroissant :

$ sort /etc/passwd -t":" -k3 -n -r

Notez bien ces deux options importantes de sort :

  • -u: fournit un ordre strict : les doublons sont écartés ;

  • -f: ignore la casse (ne fait pas de différence entre minuscules et majuscules).

Enfin, si nous voulons trouver l'utilisateur ayant l'identifiant UID le plus élevé :

$ sort /etc/passwd -t":" -k3 -n |tail -n1

Nous trions le fichier /etc/passwd par ordre d'UID ascendant, et redirigeons le résultat sur un tube pour la commande tail qui ne laisse passer que la première ligne.



[26] Certains exemples de cette section s'appuient sur des tâches réelles et des fichiers journaux serveur (services, démons). Assurez-vous que le démon syslogd est lancé (il permet aux autres démons d'écrire leurs journaux), ainsi que le démon dont il est question (ici Postfix), et que vous travaillez en tant que root. Bien entendu, vous pouvez toujours appliquer nos exemples à d'autres fichiers.

[27] Par exemple, le fichier /var/log/mail/info enregistre toutes les informations à propos des messages envoyés, messages rapatriés par les utilisateurs avec le protocole POP, etc.

[28] Même s'il est possible de ne filtrer qu'à l'aide d'une séquence, nous désirons vous montrer une nouvelle commande par cet exemple.

[29] Nous ne parlons que brièvement de sort ici. Des livres entiers pourraient être écrits sur le sujet.