original in es Manuel Muriel Cordero
es to fr Georges Tarbouriech
Manuel Muriel Cordero est étudiant à la Faculté d'Informatique et de Statistiques de Séville.
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.
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é
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.
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 -> *"'?<
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.
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.
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
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
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
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 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 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.
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.
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.
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
Le Seigneur des Anneaux . Auteur J.R.R Tolkien . Editions Presses Pocket (c) 1991