Utilitaires GNU

ArticleCategory:[Categoría del Artículo]

UNIX Basics

AuthorImage:[Fotografía del Autor]

[Foto del Autor]

TranslationInfo:[Historia de traducción]

original in es Manuel Muriel Cordero

es to fr Georges Tarbouriech

AboutTheAuthor:[Sobre el Autor]

Manuel Muriel Cordero est étudiant à la Faculté d'Informatique et de Statistiques de Séville.

Abstract:[Resumen]

ArticleIllustration:[Ilustraci'on de Cabecera]

[Ilustracion]

ArticleBody:[Contenido del Articulo]

Dans l'article précédent de cette série nous avons passé en revue les aspects les plus généraux de Linux. Nous y présentions les connaissances minimales pour commencer à maîtriser l'utilisation du système d'exploitation. L'utilisateur peut vouloir en savoir plus sur les outils classiques d'Unix, et par extension de Linux, afin de pouvoir mieux contrôler la gestion des fichiers. Dans cet article, nous essayons d'expliquer le fonctionnement d'un ensemble d'outils un peu plus évolués bien que basiques permettant de remplir cette fonction.

Introduction. La méthode de travail d'Unix.

Avant de commencer à les détailler, le lecteur doit connaître le pourquoi des particularités d'Unix. Lorsque Ken Thompson et Dennis Ritchie ont crée Unix au début des années soixante-dix, ils avaient en tête l'élaboration d'un système d'exploitation destiné à faciliter le travail des programmeurs. Ils sont arrivés à la conclusion que le meilleur moyen consistait à élaborer un ensemble défini de petits outils, chacun exécutant une tâche déterminée. En réunissant ces outils on peut réaliser des travaux plus complexes si les résultats de certaines tâches sont convertis en entrées d'autres tâches par l'intermédiaire d'une communication.

Ce moyen de transmettre l'information s'effectue par l'utilisation des entrées et sorties standards (écran et clavier). Mais c'est grâce à l'existence des "pipes" et des redirections (vus dans l'article précédent) que l'on obtient ces résultats.

Nous pouvons le vérifier par un exemple. Si un utilisateur tape cette ligne:

$ who | grep pepe

who et grep sont deux programmes distincts séparés par le "pipe" "|". who nous montre une liste des utilisateurs connectés à l'ordinateur au moment donné. Sa sortie habituelle serait semblable à:

$ who
manolo	tty1	Dec 22	13:15
pepe	ps/2	Dec 22	14:36
root	tty2	Dec 22	10:03
pepe	ps/2	Dec 22	14:37

Ce que renvoie who est divisé en 4 champs séparés par des tabulations. Ce sont le nom de l'utilisateur (login), le terminal sur lequel il est connecté, la date et l'heure du début de la connexion.

"grep pepe" de son côté, cherche les lignes de cette sortie qui contiennent la chaîne "pepe".

La sortie devient alors:

$ who | grep pepe
pepe	ps/2	Dec 22	14:36
pepe	ps/2	Dec 22	14:37

Par exemple, si maintenant l'utilisateur préfère quelque chose de plus simple, à savoir qui est connecté ou non d'après le nombre de connexions à ce moment précis, il doit se servir de l'utilitaire wc.

wc est un compteur de lettres, de mots et de lignes. Comme dans ce cas nous ne voulons connaître que le nombre de lignes, il faut utiliser l'option -l.

$ who | grep pepe | wc -l
	2

pepe est connecté sur 2 terminaux.

Si maintenant nous essayons avec antonio

$ who | grep antonio | wc -l
	0

antonio n'est pas connecté

Origine des utilitaires GNU

Richard Stallman, fondateur du projet GNU, a remarqué que la tyranie des grandes entreprises de développement logiciel sur le marché, en plus d'être éthiquement discutable, empêche une avancée rationnelle de l'informatique. Travaillant au MIT sur le développement de l'éditeur Emacs, il ne souhaitait pas voir son travail utilisé par des marques commerciales pour en faire des versions propriétaires. A partir de cet état de fait, il a décidé de créer un projet dont le but était de rendre le code source des programmes accessible à tout le monde. Son objectif était de créer un système d'exploitation ouvert. Le travail a commencé par le développement d'une version libre d'Emacs, d'un compilateur (GCC) et de l'ensemble des outils caractéristiques des systèmes Unix. Ce sont ces outils que nous nous proposons d'analyser dans cet article.

grep

Dans l'exemple précédent nous avons pu voir l'utilité basique de grep. Entrons maintenant dans les détails.

grep fonctionne de cette manière:

$ grep [-options] modèle fichiers

Les options les plus courantes sont:

-n ajoute à chaque ligne son numéro de ligne (utile pour chercher quelque chose dans un très gros fichier et savoir précisément où ça se trouve)
-c n'affiche que le nombre d'occurrences trouvées
-v permet de chercher les non correspondances ( quand ce que nous cherchons ne doit pas correspondre au modèle)

Le modèle est la chaîne de caractères recherchée. Il faut préciser que s'il existe un espace dans la chaîne, grep confondra le modèle avec les fichiers à rechercher, par conséquent il faut utiliser des guillemets (""). Par exemple:

$ grep "Bonjour le monde" fichier

Si nous recherchons une chaîne contenant un joker, des apostrophes, des guillemets, des redirections ou un anti-slash "\", il faudra faire précéder la chaîne d'un "\" pour indiquer que nous recherchons ce caractère proprement dit et non la substitution du joker, ou bien que nous commençons une chaîne de plusieurs mots.

$ grep \*\"\'\?\< fichier
Voici une chaîne pour rire -> *"'?<

Expressions régulières

grep et d'autres outils GNU sont capables d'effectuer des recherches plus élaborées. Ceci est obtenu grâce aux expressions régulières. Les expressions régulières remplissent une fonction comparable aux jokers dans le shell, c'est-à-dire substituent des caractères ou des ensembles de caractères. Quelques exemples:

$ grep c.n 

recherche toutes les occurrences contenant une chaîne avec un c, n'importe quelle autre lettre et un n.

$ grep [Bc]el

recherche les occurrences Bel et cel.

$ grep [m-o]ata

Renvoie les lignes contenant mata, nata et oata.

$ grep [^m-o]ata

Renvoie les lignes contenant une chaîne terminée par ata et qui ne commencent pas par m et o.

$ grep "^Martin come"

La sortie affichera les lignes commençant par Martin come; attention, remarquez que ce n'est pas entre crochets, dans ce cas ce n'est pas une négation comme dans l'exemple antérieur mais un début de ligne.

$ grep "endormi$"

Trouvera les lignes terminées par endormi. $ correspond à une fin de ligne.

$ grep "^Caja San Fernando gagne le championnat$"

Recherche ces lignes à l'identique.

Bien sûr, ces caractères doivent être précédés de l'anti-slash ("\") obligatoire pour éliminer leur propriété de substitution. Par exemple:

$ grep "E\.T\."

Recherchera la chaîne E.T.

Find

Cette commande se charge de la recherche de fichiers. Dans un autre article de ce magazine elle a été expliquée de manière assez détaillée. Comme il ne s'agit pas de réinventer la roue, nous nous contenterons d'y faire référence.

Couper et coller

Dans Unix l'information était conservée dans des fichiers texte ASCII organisés en champs verticaux coupés par des séparateurs, ces derniers pouvant être une tabulation ou deux points ":". L'une des nécessités pouvant se présenter dans ces cas-là consiste à séparer les champs d'un fichier afin de les regrouper dans un autre. C'est le rôle de couper et coller.

Nous allons utiliser comme exemple le fichier /etc/passwd chargé de la gestion des utilisateurs. Son contenu se compose de 7 champs séparés par ":". Les champs se présentent dans cet ordre: login, mot de passe crypté, identification de l'utilisateur, identification du groupe, nom en clair, répertoire de l'utilisateur et shell utilisé.

Voici un extrait type de ce fichier.

root:x:0:0:root:/root:/bin/bash
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
practica:x:501:501:Utilisateur de test pour Ksh:/home/practica:/bin/ksh
wizardi:x:502:502:Wizard pour nethack:/home/wizard:/bin/bash

Maintenant, si nous voulons par exemple regrouper les utilisateurs par leur login nous devons couper les champs 1 et 7. Au travail:

$ cut -f1,7 -d: /etc/passwd
root:/bin/bash
murie:/bin/bash
practica:/bin/ksh
wizard:/bin/bash

-f spécifie les champs à visualiser, -d indique le séparateur à utiliser (par défaut la tabulation) et en dernier on trouve le fichier à lister.

Il est aussi possible de spécifier les intervalles entre les champs:

$ cut -f5-7 -d: /etc/passwd
root:/root:/bin/bash
Manuel Muriel Cordero:/home/murie:/bin/bash
Utilisateur de test pour Ksh:/home/practica:/bin/ksh
Wizard pour nethack:/home/wizard:/bin/bash

Laissons comme exercice au lecteur le pourquoi de cette sortie.

Supposons maintenant que nous ayons redirigé la sortie vers 2 fichiers grâce à ">" et que nous voulions les regrouper. Pour cela nous avons "coller" (paste).

$ paste sortie1 sortie2
root:/bin/bash:root:/root:/bin/bash
murie:/bin/bash:Manuel Muriel Cordero:/home/murie:/bin/bash
practica:/bin/ksh:Utilisateur de test pour Ksh:/home/practica:/bin/ksh
wizard:/bin/bash:Wizard pour nethack:/home/wizard:/bin/bash

sort

Supposons par exemple que nous souhaitions maintenant classer /etc/passwd sur le nom en clair. Pour cela, nous allons utiliser sort, l'outil de tri.

$ sort -t: +4 /etc/passwd
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
practica:x:501:501:Utilisateur de test pour Ksh:/home/practica:/bin/ksh
wizard:x:502:502:Wizard pour nethack:/home/wizard:/bin/bash
root:x:0:0:root:/root:/bin/bash

Nous pouvons noter que la sortie est triée, mais selon le critère de la table ASCII; si nous voulions un tri sans différenciation de majuscules et minuscules nous le ferions ainsi:

$ sort -t: +4f  /etc/passwd
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
root:x:0:0:root:/root:/bin/bash
practica:x:501:501:Utilisateur de test pour Ksh:/home/practica:/bin/ksh
wizard:x:502:502:Wizard pour nethack:/home/wizard:/bin/bash

-t est l'option qui indique le séparateur utilisé. +4 donne le nombre de champs à ignorer avant de commencer le tri. f signifie que la différence entre majuscules et minuscules est ignorée.

Nous pouvons effectuer un tri beaucoup plus raffiné. Par exemple, classer d'abord de manière inversée selon le shell utilisé et ensuite par le nom en clair:

$ sort -t: +6r +4f /etc/passwd
practica:x:501:501:Utilisateur de test pour Ksh:/home/practica:/bin/ksh
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
root:x:0:0:root:/root:/bin/bash
wizard:x:502:502:Wizard pour nethack:/home/wizard:/bin/bash

Supposons maintenant que nous disposions d'un fichier dans lequel figurent les personnes vous devant des intérêts d'emprunt. Un exemple "manga":

Son Goku:23450
Son Gohan:4570
Picolo:356700
Ranma 1/2:700

Si vous souhaitez savoir auquel vous devez d'abord envoyer l'huissier :-) vous voudrez obtenir une sortie triée selon le retard de paiement.

Si nous effectuons ce test nous pouvons observer que:

$ sort +1 intérêts
Ranma 1/2:700
Son Gohan:4570
Son Goku:23450
Picolo:356700

Ce n'est pas précisément ce que nous attendions puisque nous avons trié alphabétiquement avec un nombre de chiffres différent. La solution réside dans l'option n:

$ sort +1n intérêts
Picolo:356700
Son Goku:23450
Son Gohan:4570
Ranma 1/2:700

Les options de base de sort sont les suivantes

+n.m saute les n premiers champs et les m caractères suivants avant de commencer le tri.
-n.m pour le tri à partir du n-ième champ et des m caractères suivants

et pour modifier les paramètres:

-b ignore les espaces
-d tri de dictionnaire ( seules sont prises en compte les lettres, les chiffres et les espaces)
-f ignore la distinction entre majuscules et minuscules.
-n tri arithmétique
-r tri inverse

wc

Comme nous l'avons vu, wc est un compteur de lettres, lignes et mots. En donnant un fichier comme paramètre, la sortie par défaut fournit le nombre de lignes, de mots et de caractères qui le composent.

Avec les options nous pouvons modifier la sortie

-l ne donne que le nombre de lignes
-w ne donne que le nombre de mots
-c ne donne que le nombre de caractères

Outils de différenciation: cmp,comm,diff

Il est parfois nécessaire de connaître les différences entre 2 versions d'un fichier. C'est particulièrement utilisé en programmation lorsque plusieurs personnes travaillent sur un même projet et modifient les sources des programmes. Si l'on souhaite connaître les variantes d'une version à l'autre on utilise ces outils.

cmp est la plus basique. Elle compare deux fichiers et indique, s'il existe, l'endroit où intervient la première différence (numéros du caractère et de la ligne)

$ cmp ancien nouveau
ancien nouveau differ: char 11234, line 333

comm est un peu plus évolué. Sa sortie s'effectue sur 3 colonnes. La première contient les lignes uniques du premier fichier, la seconde les lignes uniques du deuxième fichier et la troisième les lignes communes. Elle dispose de paramètres qui précisent si l'on veut éliminer une de ces colonnes. -1, -2 et -3 indiquent à comm de ne pas afficher la première, la seconde ou la troisième colonne. Dans cet exemple nous ne voyons que les lignes du premier fichier et les lignes communes.

$ comm -2 ancien nouveau

Pour finir, voici diff. C'est un outil fondamental dans la programmation de projets avancés. Si vous avez déjà téléchargé un noyau pour le compiler vous savez que vous pouvez récupérer les sources du nouveau ou récupérer le patch pour la version antérieure, qui normalement est plus petit. Le patch se termine habituellement par .diff, ce qui indique qu'il est le résultat d'une sortie de diff. Cet outil comporte une série de commandes d'éditeur (vi, rcs) de manière à ce que les fichiers soient identiques. C'est applicable aussi aux répertoires et aux archives qui les contiennent. L'utilité est très claire: on télécharge une quantité inférieure de source (juste les modifications), on applique le correctif (le patch) et on recompile. Sans paramètres, la sortie spécifie dans ces formats comment doivent se faire les correctifs de manière à ce que le premier soit identique au second avec des commandes vi.

$ diff ancien nouveau
3c3
< Le Hobbit
---
> Le Seigneur des Anneaux
78a79,87
> Trois Anneaux pour les Rois Elfes sous le ciel,
> Sept pour les Seigneurs Nains dans leurs demeures de pierre,
> Neuf pour les Hommes Mortels destinés au trépas,
> Un pour le Seigneur des Ténèbres sur son sombre trône
> Dans le Pays de Mordor où s'étendent les Ombres.
> Un Anneau pour les gouverner tous. Un Anneau pour les trouver,
> Un Anneau pour les amener tous et dans les ténèbres les lier
> Au Pays de Mordor où s'étendent les Ombres.

3c3 signifie que l'on doit changer la ligne 3 , en supprimant "Le Hobbit" et en lui substituant "Le Seigneur des Anneaux". 78a79,87 signifie que l'on doit insérer de nouvelles lignes de la ligne 79 à la 87.

uniq

uniq est celui qui est chargé d'éliminer les redondances. Par exemple, si nous souhaitons obtenir une liste des personnes connectées à l'ordinateur à un moment donné nous devrons utiliser who et cut.

$ who | cut -f1 -d' '
root
murie
murie
test

Le résultat n'est pas parfait. Il reste à éliminer la double apparition de murie. Il suffit de demander.

$ who | cut -f1 -d' ' | uniq
root
murie
test

Il faut préciser que le -d' ' signifie que le séparateur est l'espace puisque who ne sait pas séparer par tabulations.

sed

sed est un des outils les plus particuliers d'Unix. sed signifie Stream Editor (Editeur de flux). Les éditeurs acceptent habituellement les modifications de manière interactive. sed nous permet de créer de petits programmes "shell scripts" semblables aux fichiers batch de MS-DOS. sed nous offre la possibilité de modifier automatiquement le contenu d'un fichier, par la création de scripts shell qui le modifieront à la volée. Les capacités de cet éditeur sont très complètes et à cause de l'ampleur que prendrait cet article nous ne les traiterons pas ici; nous nous contenterons d'une brève introduction laissant l'utilisateur intéressé recourir à la documentation des pages man et info de Linux concernant toutes ses commandes.

On appelle Sed de cette manière:

$ sed 'commande-sed' fichier

Nous avons par exemple un fichier dans lequel nous souhaitons remplacer toutes les apparitions de "Manolo" par "Fernando". Au travail:

$ sed 's/Manolo/Fernando/g' archive

Et il renvoie les modifications par la sortie standard. Si l'on veut conserver le résultat on le redirige par ">"

Les utilisateurs de vi reconnaîtront immédiatement qu'il s'agit d'une commande type de vi pour la recherche et le remplacement. En réalité les commandes du type ":" (celles qui invoquent ex) peuvent être utilisées dans sed.

La structure des ordres de sed consiste à indiquer d'abord une chaîne (ou une séquence de chaînes) sur laquelle travailler et ensuite la commande. Pour signaler une chaîne on peut donner un nombre, un intervalle entre des nombres ou rechercher un modèle.

Les commandes courantes de sed
Commande Action
-------  ------
a\	ajoute les lignes suivantes aux lignes sélectionnées
c\	remplace les lignes sélectionnées par les lignes suivantes
d	efface les lignes sélectionnées
g	remplace globalement tous les modèles localisés au lieu 
	de se limiter au premier
i\	insère les lignes suivantes aux lignes sélectionnées
p	imprime la ligne, y compris avec l'option -n
q	abandonne (quit) en atteignant la ligne spécifiée
r fichier 	lit un fichier, ajoutant le contenu à la sortie
s/un/deux	remplace la chaîne "un" par "deux"
w fichier	copie cette ligne dans un autre fichier
=	imprime le numéro de ligne
! commande	applique une commande à la ligne dite

Avec sed on peut spécifier à quelle ligne ou ensemble de lignes s'applique la commande:

$ sed '3d' archive

Effacera la troisième ligne de l'archive

$ sed '2,4s/e/#/' fichier

Remplace le caractère e par # dans les lignes 2 à 4 incluses.

Il est aussi possible d'effectuer des commandes sur des lignes qui contiennent une chaîne donnée, en utilisant, si on le souhaite, des expressions régulières expliquées précédemment.

$ sed '/[Qq]ueen/d' chansons

Efface toutes les lignes qui contiennent la chaîne "Queen" ou "queen".

Grâce aux expressions régulières nous pouvons par exemple éliminer les lignes vides d'un fichier.

$ sed '/^$/d' archive

Bien que cela n'effacera pas les chaînes contenant des espaces. Avec cette version, on atteint ce but.

$ sed '/^ *$/d' archive

La séquence ' *' signifie que l'on doit chercher toute combinaison de zéro ou plus d'apparitions du modèle ' '.

$ sed '/InitMenu/a\
> gvim	gvim.xpm	exec gvim &'  .xvwmrc

Cet exemple rechercherait une ligne contenant la chaîne InitMenu et ensuite
lui ajouterait cette chaîne.

awk

La dernière et non la moindre est la commande awk. Pour ceux qui s'étonnent de ce nom particulier, il provient du nom de ses créateurs: Alfred Aho, Brian Kernighan et Peter Weinberger.

L'utilitaire awk est l'un des plus intéressants des systèmes Unix. C'est un outil assez complexe et élaboré qui permet de réaliser un ensemble varié d'opérations à partir de la ligne de commande.

Il faut signaler que awk et sed sont des pièces clé des scripts shell les plus complexes. Ce que l'on peut réaliser sans faire usage du C ou de n'importe quel autre langage compilé est réellement impressionnant. Mentionnons par exemple que l'installation de la distribution slackware et de nombreux CGI sur le web sont en réalité des scripts shell.

Ces derniers temps l'usage des outils en ligne de commande est devenu plutôt désuet, lui reprochant sa trop grande ancienneté par rapport aux environnements graphiques d'aujourd'hui, ainsi que l'arrivée du langage Perl présenté comme un remplaçant des scripts shell tendent à condamner ces outils à l'oubli. Par expérience j'ai pu vérifier que de nombreuses applications (y compris un petit gestionnaire de base de données) n'ont besoin que de peu de lignes de code en scripts shell.

C'est là que awk lié à sed peuvent réaliser un gros travail sur des informations stockées au format ASCII. Avec eux nous pouvons faire des travaux équivalents au cumul d'un petit gestionnaire de base de données et d'une feuille de calcul.

Imaginons une facture dans laquelle on indique dans un fichier les articles achetés et leurs prix de vente public. Par exemple ce fichier "achats":

oranges	5	250		
poires	3	120
pommes	2	360

Il s'agit d'un fichier de 3 champs séparés par des tabulations. Maintenant nous voulons créer un quatrième champ avec le prix total de chaque produit.

$ awk '{total=$2*$3; print $0 , total }' achats
oranges	6	250	1250
poires	3	120	360
pommes	2	360	720

total est une variable à laquelle on assigne les valeurs multipliées des champs deux et trois, ensuite pour chaque ligne on imprime la ligne complète ($0) et le total par ligne.

Awk est pratiquement un environnement de développement à lui-seul, idéal pour le traitement automatisé d'information en fichiers texte. Si l'utilisateur a découvert cet outil avec intérêt, je l'encourage à continuer la recherche de ses particularités dans les pages man et info de son système.

Les scripts shell

Nous y avons déjà fait référence. Les scripts shell sont des séquences d'instructions (commandes du système) qui doivent s'exécuter.

Les scripts shell sont les frères des fichiers batch du DOS. Avec eux, l'utilisateur a tout ce qu'il faut pour créer ses propres commandes à partir de la combinaison d'autres.

Les scripts shell sont capables, disons, d'accepter des paramètres stockés dans les variables $0 (numéro des commandes) $1, $2,..., $9. Pour se référer à ceux de $1 à $9 on peut utiliser $*.

Les scripts shell peuvent être crées avec n'importe quel éditeur. Pour les exécuter on peut procéder ainsi:

$ sh shell-script

ou mieux, accorder les droits d'exécution au fichier par

$ chmod 700 shell-script

Ensuite il peut s'exécuter simplement par

$ shell-script

Pour l'instant, laissons les scripts shell pour terminer cet article. Dans des numéros ultérieurs nous reviendrons sur le sujet. Dans le prochain article nous parlerons des éditeurs les plus courants d'Unix. Vi et emacs. La connaissance de leur fonctionnement est fondamentale pour tout utilisateur de Linux.

Ressources

Cet article est une introduction et si le lecteur le souhaite, il peut approfondir le sujet grâce à d'autres articles de LinuxFocus tels que: Find Expressions regulières Awk

Bibliographie:

Le Seigneur des Anneaux . Auteur J.R.R Tolkien . Editions Presses Pocket (c) 1991