IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Pour aller plus loin avec la ligne de commande

Tout ce que vous avez toujours voulu savoir sur Unix sans jamais oser le demander


précédentsommairesuivant

3. Chapitre 3 - La boîte à outils

Cut prints selected parts of lines
from each FILE to standard output.
With no FILE, or when FILE is -,
read standard input.
man cut.

L'idée conductrice des développeurs d'unix de la première heure était de concevoir des outils élémentaires destinés à une tâche bien spécifique ; chacun de ces outils devait être conçu de telle manière qu'il puisse communiquer avec les autres. En tant qu'utilisateur d'unix on retrouve cette philosophie à tout moment : chaque utilitaire, à l'instar d'une pièce de meccano®, est destiné à effectuer une tâche simple et la connaissance de quelques pièces permet de construire ses propres outils. Ce chapitre a pour objet de présenter les mécanismes qui permettent de faire communiquer ces programmes entre eux, puis de présenter les pièces de la boîte à outils les plus communément utilisées sous unix. 

3-1. Introduction à l'expansion

Avant d'aborder l'étude de quelques outils unix, il convient de comprendre quelques-uns des mécanismes entrant en jeu dans l'interprétation des commandes. Comme nous l'avons vu précédemment, certains caractèresCaractères spéciaux ont une signification particulière pour le shell. Lorsqu'on veut utiliser ces caractères autrement que pour leur signification spéciale, il faut généralement utiliser le caractère backslash (\) :

 
Sélectionnez
$ echo \*
*
$

Sans le backslash, le caractère * aurait été remplacé par tous les fichiers du répertoire courant. Un moyen couramment utilisé avec le shell pour protéger les caractères spéciaux est d'utiliser les caractères quote ' et double quote ". Le premier évite l'expansion de tout caractère :

 
Sélectionnez
$ echo '$USER #'
$USER #
$

Le deuxième permet au caractère $ de conserver sa signification :

 
Sélectionnez
$ echo "$USER #"
lozano #
$

Il sera souvent question de protéger les caractères spéciaux lors de l'utilisation des outils que nous présentons dans ce chapitre. 

3-2. Redirections et tubes

Par défaut, tout processus a accès à trois canaux de communications (figure 3.1) : 

Image non disponible
Figure 3.1 - Les trois flux associés à un processus
  1. le flux de sortie (standard output) par défaut dirigé vers le terminal courant ;
  2. le flux d'erreur (standard error) également dirigé par défaut vers le terminal courant ;
  3. le flux d'entrée (standard input) sur lequel transitent par défaut les données provenant du clavier.

Ainsi, la commande :

 
Sélectionnez
$ echo bonjour
bonjour
$

affiche « bonjour » sur le flux de sortie. La commande :

 
Sélectionnez
$ ls amlkjg
ls: amlkj: No such file or directory
$

affiche le message sur le flux d'erreur. Et la commande (du shell bash) :

 
Sélectionnez
$ read A
hop là  <--------------------------------------- saisie par l'utilisateur
$

attend la saisie d'une ligne sur le flux d'entrée, ligne qui sera stockée dans la variable A.

Ce qu'il est intéressant de comprendre, c'est que la grande majorité des commandes et utilitaires d'unix suivent le modèle de ces trois flux standard, qu'on pourrait définir de la manière suivante :

  • tout affichage est envoyé par défaut sur le flux de sortie ;
  • tout message d'erreur est envoyé sur le flux d'erreur ;
  • toute donnée peut être lue depuis le flux d'entrée.

À titre d'exemple, la commande grep suit ce modèle. Cette commande est destinée à ne récupérer que les lignes d'un fichier contenant une chaine de caractèresgrep et la notion d'expressions régulières :

  1. grep affiche le résultat sur le flux de sortie ;
  2. les messages d'erreurs éventuels sont affichés sur le flux d'erreur ;
  3. grep peut attendre les données à filtrer sur son flux d'entrée :
 
Sélectionnez
$ grep bof  <------------------------- on recherche la chaîne bof
xxxbofyyy Entrée  <--------------------- saisie par l'utilisateur
xxxbofyyy  <-------------- correspondance : grep affiche la ligne
xxxbifyyy Entrée  <--------------------- saisie par l'utilisateur
 <----------------------------------------- pas de correspondance

On peut indiquer à une commande qui attend des données sur son flux d'entrée, la fin des données à l'aide du caractère EOF saisi par la combinaison de touches Image non disponible Image non disponible.

Nous verrons par la suite que c'est précisément parce que la plupart des commandes unix suit ce modèle des trois flux, qu'on peut composer les utilitaires avec une grande souplesse. Cette « composabilité » qui fait la grande force d'unix est possible grâce à ce qu'on appelle les redirections.

3-2-1. Redirections

Il est possible de rediriger les trois flux présentés au paragraphe précédent, grâce à une syntaxe particulière qui varie très légèrement selon le shell utilisé.  

3-2-1-a. Redirection du flux de sortie

On peut rediriger le flux de sortie vers un fichier :

 
Sélectionnez
$ echo bonjour > test.txt
$ ls -l test.txt
-rw-r--r-- 1 vincent users 8 Dec 11 16:19 test.txt
$

Le caractère > permet la redirection dans le fichier test.txt. On peut noter que le choix du caractère évoque la direction du flux « vers » le fichier. Puis :

 
Sélectionnez
$ more test.txt
bonjour
$

La commande moreAfficher qui a pour but d'afficher le contenu d'un fichier à l'écran, permet ici de comprendre que echo a réalisé son affichage dans le fichier test.txt et non à l'écran. 

3-2-1-b. Redirection du flux d'erreur

On peut dans certaines situations vouloir récupérer les informations envoyées par un programme sur le flux d'erreur. Le principe est le même que pour le flux de sortie, seul l'opérateur est différent :

 
Sélectionnez
$ ls qsmlkjf 2> erreur.txt
$ cat erreur.txt
ls: qsmlkjf: No such file or directory
$

On peut également coupler les deux redirections de la manière suivante :

 
Sélectionnez
unprogramme > sortie.txt 2> erreur.txt

Pour rediriger les deux flux (sortie et erreur) dans un même fichier, on pourra utiliser :

 
Sélectionnez
unprogramme > sortie-erreur 2>&1

Ou plus simple :

 
Sélectionnez
unprogramme >& sortie-erreur
 
3-2-1-c. Redirection en mode ajout

L'opérateur > crée ou écrase le fichier destinataire de la redirection. On peut cependant utiliser le mode « ajout » (append) pour ne pas écraser un fichier déjà existant :

 
Sélectionnez
$ echo bonjour > donnees.txt
$ echo salut >> donnees.txt
$ cat donnees.txt
bonjour
salut
$
 
3-2-1-d. Redirection du flux d'entrée

Lorsqu'un programme attend des données depuis le clavier, on peut lui fournir directement ces données en utilisant le contenu d'un fichier. On dit alors qu'on redirige le flux d'entrée du programme en question. Le premier exemple que nous proposons utilise la commande bc qui est d'après la page de manuel, an arbitrary precision calculator language. Une session avec bc se présente comme suit :

 
Sélectionnez
$ bc -q
2+3*5 Entrée
17
quit
$

Si on stocke l'expression du calcul (2+3*5) dans un fichier, on peut indiquer à bc que les données proviennent de ce fichier : 

 
Sélectionnez
$ cat calcul.dat
2+3*5
$ bc < calcul.dat
17
$

On dit qu'on a redirigé le flux d'entrée de bc depuis le fichier calcul.dat.

Le second exemple concerne la commande mail. Pour envoyer un mail en utilisant cette commande, le principe est le suivant :

 
Sélectionnez
$ mail -s "Des redirections" monpote
Bon ben alors...
A+
.
EOT
$

l'option -s permet de spécifier le sujet. L'argument qui suit (monpote) est l'adresse électronique du destinataire du mail. Une fois la commande lancée, on peut taper le texte du message ; le caractère « . » sur une seule ligne permet de finir le texte et d'envoyer le message.

La version originelle de mail ne dispose pas de l'option -s, cette option apparaît dans le programme standard mailx. Sur le système LINUX de votre serviteur mailx et mail font référence au même programme. Attention par contre, d'autres systèmes peuvent être configurés différemment.

Ce qu'il faut comprendre ici, c'est que mail attend le texte du message sur le flux d'entrée. On peut alors rediriger cette entrée « depuis » un fichier qui contiendrait le corps du message :

 
Sélectionnez
$ cat msg.txt  <------------------------ msg.txt contient le message
alors voilà
A+
$ mail -s "redirections" monpote < msg.txt
$

Donc en supposant que l'on ait saisi le message dans le fichier msg.txt, la dernière commande mail peut se traduire par « envoyer un mail en lisant les données depuis le fichier msg.txt ». On dit alors qu'on a redirigé le flux d'entrée. 

3-2-1-e. Le trou noir

On trouve généralement sur les systèmes unix un fichier particulier dont le nom est /dev/null : c'est un « trou noir » qui absorbe toute redirection sans broncher ; ce fichier est un fichier spécial, il ne grossit pas lorsqu'on y redirige des données. Il peut être utile pour ne pas être dérangé par les messages d'erreur par exemple :

  • id user > test 2> /dev/null

cette commande écrit dans le fichier test les numéros identifiant l'utilisateur user. Si l'utilisateur n'existe pas le message d'erreur n'est pas affiché puisqu'envoyé dans /dev/null. 

3-2-2. Les tubes (pipes)

Les tubes ou pipes offrent un mécanisme permettant de composer plusieurs commandes en connectant le flux de sortie de l'une avec le flux d'entrée de la suivante (figure 3.2).

Reprenons l'exemple de l'envoi du mail du paragraphe précédent. Supposons que nous disposions de deux fichiers de données contenant :

 
Sélectionnez
$ more data-I.txt
machin
chose
$
Image non disponible
Figure 3.2 - Principe des tubes

et :

 
Sélectionnez
$ more data-II.txt
bidule
chouette
$

On veut envoyer ces deux fichiers au sieur monpote. Pour ce faire : 

 
Sélectionnez
$ cat data-I.txt data-II.txt | mail -s "some data" monpote
$

La sortie de la commande cat - qui réalise la concaténation des données des fichiers data-I.txt et data-II.txt - est utilisée comme entrée de la commande mail (corps du message). On peut composer à l'« infini » les tubes comme le montre l'exemple suivant : on veut également envoyer une copie des données triées au gars monpote. Le tri peut être fait par la commande sortTrier :

 
Sélectionnez
$ sort data-I.txt data-II.txt
bidule
chose
chouette
machin
$

On peut donc exploiter le fait que sort peut trier les données arrivant sur le flux d'entrée, pour envoyer le mail avec deux tubes :

 
Sélectionnez
$ cat data-I.txt data-II.txt | sort | mail -s "some data" monpote
$

donc ici, la sortie de cat est utilisée comme entrée pour sort qui envoie à mail le corps du message sur le flux d'entrée. Notez enfin qu'on aurait pu écrire :

 
Sélectionnez
$ sort data-I.txt data-II.txt | mail -s "some data" monpote
$

car sort est capable de trier les fichiers qu'on lui passe en arguments. L'exemple avait ici pour but de combiner plusieurs tubes.

Un point important à noter est que lors de l'utilisation de plusieurs commandes par l'intermédiaire de tubes, chacune des commandes est lancée en même temps par le système. Bien que l'on imagine visuellement un flux d'information transitant de gauche à droite, les commandes sont lancées de manière concurrente.

Toute utilisation « sérieuse » du shell d'unix passe par une utilisation fréquente des tubes et redirections. Les utilitaires présentés dans la suite de ce chapitre peuvent se voir comme des filtres, c'est-à-dire que l'on peut considérer qu'ils filtrent le flux de sortie des programmes auxquels ils s'appliquent. En d'autres termes, un filtre peut être utilisé avec un tube puisqu'il attend systématiquement des données sur son flux d'entrée et envoie le résultat du « filtrage » sur son flux de sortie. 

3-3. Les outils de base

Nous donnons ici quelques outils fréquemment utilisés sous unix dont il faut connaître l'existence. Chacun de ces outils est présenté avec quelques options, également les plus communes. Pour une utilisation avancée il faudra se référer aux pages de manuelChapitre 7 - À l'aide !. Nous utiliserons pour les exemples le fichier suivant :

 
Sélectionnez
$ cat fichier.dat
Jimi Hendrix 1970
Jim Morrison 1971
Janis Joplin 1969
$
 

3-3-1. Afficher

Le rôle de la commande cat est de concaténer (concatenate) plusieurs fichiers. Le résultat de cette concaténation étant envoyé sur le flux de sortie. Ainsi :

  • cat fichier1 fichier2 fichiern

concatène les fichiers de 1 à n et les affiche sur le flux de sortie. Le filtre more peut être utilisé lorsque l'affichage est trop long pour le terminal. Les fichiers sont alors affichés page par page :

  • cat fichier1 fichier2 | more

Selon les systèmes on peut utiliser la commande less(48) (plus ergonomique) à la place de more. 

3-3-2. Trier

C'est la commande sort :

 
Sélectionnez
$ sort fichier.dat
Janis Joplin 1969
Jimi Hendrix 1970
Jim Morrison 1971
$

Par défaut les lignes sont classées selon la première colonne. On peut classer selon les noms :

 
Sélectionnez
$ sort -k2 fichier.dat
Jimi Hendrix 1970
Janis Joplin 1969
Jim Morrison 1971
$

L'option -k pour key en anglais spécifie la clef du tri. Pour trier selon les dates :

 
Sélectionnez
$ sort -n -k3 fichier.dat
Janis Joplin 1969
Jimi Hendrix 1970
Jim Morrison 1971
$

Notez l'utilisation de l'option -n qui permet d'utiliser l'ordre numérique (par défaut c'est l'ordre lexicographique). L'option -u peut quant à elle être utilisée pour supprimer les doublons.

3-3-3. Découper en colonnes

La commande cut permet d'afficher une ou plusieurs colonnes d'un flux de données :

 
Sélectionnez
$ cut -d' ' -f1,3 fichier.dat
Jimi 1970
Jim 1971
Janis 1969
$

Le séparateur de colonnes est par défaut la tabulation. On peut en spécifier un autre avec l'option -d (pour délimiteur). Ici on a utilisé le caractère espace comme délimiteur. On a ensuite spécifié les champs (option -f pour field) numéro 1 et numéro 3 (respectivement prénom et date).

Voici pour s'amuser un exemple d'utilisation des tubes :

 
Sélectionnez
$ cut -d' ' -f1,3 fichier.dat | sort -k2 -n
Janis 1969
Jimi 1970
Jim 1971
$

Ce qui permet de trier par année le résultat du cut précédent… 

3-3-4. Recoller les colonnes

Supposons que l'on dispose d'un fichier :

 
Sélectionnez
$ cat groups.dat
The Experience
The Doors
Kosmik Band
$

On peut alors fusionner ce fichier avec notre fichier d'étoiles filantes :

 
Sélectionnez
$ paste -d' ' fichier.dat groups.dat
Jimi Hendrix 1970 The Experience
Jim Morrison 1971 The Doors
Janis Joplin 1969 Kosmik Band
$

On utilise ici aussi le caractère espace à la place de celui par défaut (tabulation). On pourra également se référer à la commande join qui elle, fusionne deux fichiers selon un champ commun. 

3-3-5. Compter

La commande wc (pour word count) permet de compter les caractères, les mots et les lignes d'un flux de données :

 
Sélectionnez
$ wc fichier.dat
3 9 54
$

Ce qui signifie que le fichier en question possède 3 lignes, 9 mots et 54 octets (les espaces et sauts de ligne sont comptabilisés). On peut également afficher uniquement l'un de ces nombres, par exemple le nombre de lignes :

 
Sélectionnez
$ wc -l fichier.dat
3
$

les options pour le nombre de mots et de caractères sont respectivement w (word) et c (byte).

Attention, même si aujourd'hui un caractère est encore codé sur un octet, on devrait trouver à l'avenir de plus en plus de fichiers texte dont les caractères sont codés sur plusieurs octets. Dans ce cas on pourra utiliser l'option -m (pour multibyte) pour compter le nombre de caractères et non d'octets.

 

3-3-6. Tête-à-queue

Les commandes head et tail comme leur nom l'indique, permettent d'afficher la tête ou la queue d'un fichier ou du flux d'entrée. Par exemple :

 
Sélectionnez
$ head -n 2 fichier.dat
Jimi Hendrix 1970
Jim Morrison 1971
$

affiche les deux premières lignes de notre fichier. L'option -c permet d'afficher les n premiers octets :

 
Sélectionnez
$ head -c 7 fichier.dat
Jimi He$

De manière analogue tail affiche la fin d'un flux :

 
Sélectionnez
$ tail -n 1 fichier.dat
Janis Joplin 1969
$

L'option -c est également disponible. La nuance avec la commande tail est qu'en utilisant un nombre de lignes n (ou d'octets) commençant par +, tail affiche les données à partir de la ne ligne (ou ne caractère). Ainsi :

 
Sélectionnez
 tail -n +2 fichier.dat
Jim Morrison 1971
Janis Joplin 1969
$

affiche le fichier fichier.dat à partir de la deuxième ligne. Une autre utilisation de la commande tail est la surveillance d'un fichier qui grossit. En considérant qu'un fichier data.log reçoit régulièrement des données, on peut surveiller les dernières données en utilisant l'option -f de tail :

 
Sélectionnez
$ tail -f data.log
189
123
234

On interrompt l'affichage avec Image non disponible Image non disponible. 

3-3-7. Utilitaires disques et fichiers

3-3-7-a. Chercher

Pour chercher un fichier ou un répertoire on peut utiliser la commande find. Cette commande est très puissante et permet de chercher des fichiers avec de très nombreux critères (type de fichier, nom, taille, permission, propriétaires, date de modifications, etc.). Chacun de ces critères peut être combiné par des « ou » ou des « et ». Nous ne vous proposerons ici que quelques exemples :

 
Sélectionnez
$ find ~ -name core
/home/equipe/lozano/LaTeX/test/core
/home/equipe/lozano/LaTeX/these/core
/home/equipe/lozano/LaTeX/these/src/core
/home/equipe/lozano/src/pas/core
/home/equipe/lozano/install/ummstdod/core
$

Cette commande cherche les fichiers dont le nom est core à partir du répertoire privé.

 
Sélectionnez
$ find . -name "*.tex"
./guide-unix.tex
$

Celle-ci trouve les fichiers dont l'extension est .tex à partir du répertoire courant.

Et :

 
Sélectionnez
$ find ~/cours -type d -a -name "po*"
/home/equipe/lozano/cours/pov
/home/equipe/lozano/cours/pov.bak
/home/equipe/lozano/cours/images/pov-hof
$

trouve tous les répertoires dont le nom commence par po. L'option -a couple les critères par un « et ». Cette option est implicite et peut donc être omise.

La commande find peut-être particulièrement coûteuse lorsqu'on doit scanner toute l'arborescence. C'est pour cette raison que certains unix proposent la commande locate qui utilise un fichier de données contenant l'emplacement de tous les fichiers sur le système. Ce fichier de données doit être mis à jour régulièrement (généralement une ou deux fois par jour) par cron. L'avantage de cette méthode est bien entendu la rapidité de la recherche, l'inconvénient réside dans le fait que le fichier de données n'est pas à jour en temps réel et ne contient pas d'autres informations que les noms des fichiers (et pas leur contenu).

 
3-3-7-b. Obtenir des informations

La commande du donne la taille qu'occupe un répertoire ou un fichier.

 
Sélectionnez
$ du -b guide-unix.tex
71680 guide-unix.tex
$

L'option -b affiche en octets (byte). Si l'argument de cette commande est un répertoire le calcul d'occupation disque est fait récursivement sur tous les fichiers et sous-répertoires :

 
Sélectionnez
$ du -k ~/cours
590 /home/equipe/lozano/cours/unix
380 /home/equipe/lozano/cours/c++
1755 /home/equipe/lozano/cours/images
7736 /home/equipe/lozano/cours/pov
$

L'option -k est utilisée ici pour afficher en kilo-octets. On peut obtenir le total de chaque sous-répertoire grâce à l'option -s (summarize) :

 
Sélectionnez
$ du -sh ~/cours
10M /home/equipe/lozano/cours
$

La commande df donne le taux d'encombrement des partitions relatives aux disques locauxArborescence et réseaux. L'option -h (human readable) de cette commande donne l'occupation des partitions en mégaoctets, gigaoctets, etc.

 
Sélectionnez
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda5 197M 56M 131M 30% /tmp
/dev/sda3 972M 471M 450M 51% /usr
/dev/sda6 197M 9.8M 177M 5% /var
count:/export/home0 2.8G 1.7G 1015M 63% /mnt/count/home0
count:/export/home5 969M 247M 672M 27% /mnt/count/home5
count:/export/softs 969M 238M 681M 26% /mnt/count/softs
count:/export/home6 969M 614M 305M 67% /mnt/count/home6
mailhost:/var/spool/mail
972M 53M 869M 6% /var/spool/mail
$
3-3-7-c. Archivage

Avertissement : cette section fera sans doute faire des bonds aux puristes qui diront à juste titre que les seules commandes standardisées par Posix sont pax et compress. J'ai choisi ici de présenter tar et gzip (et même bzip2) car il s'agit de commandes très répandues et également parce que j'ai l'habitude de les utiliser !

L'archivage est une tâche très fréquente lorsqu'on manipule des fichiers. unix distingue deux opérations dans l'archivage :

  1. l'archivage proprement dit qui consiste à rassembler plusieurs fichiers dans un seul, qui constitue l'archive ;
  2. la compression de l'archive pour en optimiser la taille. Cette opération doit être effectuée sauf dans de rares cas où les fichiers archivés sont déjà compressés (tas de fichiers Jpeg ou Pdf par exemple).

La première opération est réalisée par la commande tar (tape archiver, utilisée historiquement pour archiver sur bande magnétique), la deuxième par gzip(49). Nous donnerons ici un exemple très classique d'archivage : l'archivage des fichiers contenus dans un répertoire :

 
Sélectionnez
$ pwd
/home/equipe/lozano/cours/unix
$ cd ..
$ tar cvf ~/transfert/unix.tar unix  <----------- création de l'archive
unix
unix/arborescence.eps
unix/arborescence.fig
unix/flux.fig
... etc ...
$ ls -l ~/transfert/unix.tar
-rw-r----- 1 lozano equipe 768000 Dec 13 14:49 unix.tar
$ gzip ~/transfert/unix.tar  <---------------- compression de l'archive
$ ls -l ~/transfert/unix.tar.gz
-rw-r----- 1 lozano equipe 239039 Dec 13 14:49 unix.tar.gz
$

Voici quelques explications :

  • l'option c de tar crée l'archive (create) ;
  • l'option f précise que l'archive à créer est un fichier (file) (et non un enregistrement sur une bande magnétique) ;
  • l'option v (verbose) permet d'afficher les fichiers (et leur chemin) en cours d'archivage ;
  • le nom de l'archive suit (unix.tar) puis le nom du répertoire contenant les fichiers à archiver ;
  • la commande gzip compresse l'archive en la renommant avec le suffixe .gz.

L'opération de « désarchivage » se déroule en utilisant les commandes gzip et tar dans l'ordre inverse. Par exemple, pour décompacter l'archive précédente dans le répertoire ~/tmp :

 
Sélectionnez
$ cd ~/tmp
$ gzip -d ~/transfert/unix.tar.gz  <------------------ décompression
$ tar xvf ~/transfert/unix.tar  <--------------------- décompactage
unix/
unix/arborescence.eps
unix/arborescence.fig
unix/flux.fig
... etc ...
$ ls unix
Makefile disques.fig groups.dat guide-unix.tex~
Makefile~ ecoute.sh guide-unix.aux guide-unix.toc
patati.eps fichier.dat guide-unix.dvi missfont.log
... etc ...
$

Notez l'option -d de gzip pour décompresser, et l'option x de tar pour extraire (extract).

La version gnu de tar permet d'appeler gzip automatiquement grâce à l'option z, ce qui permet de réaliser l'archivage et la compression sur la même ligne de commande :

 
Sélectionnez
$ tar xfz ~/transfert/unix.tar.gz
$

On pourra également appeler bzip2 pour les archives compressées avec cet utilitaire, grâce à l'option j :

 
Sélectionnez
$ tar xfj ~/transfert/unix.tar.bz2
$

Puisque nous avons vu les tubes, les puristes rétorqueront que même sans la version gnu de tar il est possible de n'utiliser qu'une seule ligne de commande ; ceci en tirant partie du fait que gzip et tar suivent le modèle des « trois flux » :

 
Sélectionnez
$ tar cf - unix | gzip -c > ~/transfert/unix.tar.gz
$

Petites explications :

  • le caractère - indique à tar que l'archive doit être envoyé sur le flux de sortie ;
  • gzip compresse les données provenant du flux d'entrée et les envoie sur le flux de sortie grâce à l'option -c ;
  • le résultat est redirigé dans le fichier ~/transfert/unix.tar.gz.

La décompression sur une ligne de commande peut être faite comme suit :

 
Sélectionnez
$ gzip -dc ~/transfert/unix.tar.gz | tar xvf -
 

3-4. Le shell en tant que langage

Jusqu'à maintenant nous avons vu le shell comme un interpréteur de commandes qui se « contente » d'exécuter les commandes qu'on lui passe. En réalité le shell est un langage de programmation assez évolué permettant d'automatiser un grand nombre de tâches quotidiennes. Le shell (et nous parlerons ici essentiellement du shell bash) dispose donc de variables, de tableaux, de structures de contrôle (if, while, for), et également de la notion de fonctions. Toutes ces fonctionnalités sont détaillées au chapitre 5Chapitre 5 - Développer !.

Nous vous présenterons ici par le biais d'une « étude de cas » deux fonctionnalités intéressantes du shell : la substitution de commande et la boucle « pour ». Le problème est le suivant : suite à une erreur lors d'un transfert de fichier, on a dans un répertoire une liste de fichiers dont les noms sont en majuscules. On veut transformer ces noms en minuscules. L'algorithme que nous allons implémenter en langage de commande pourrait s'écrire :

Image non disponible
 

3-4-1. Afficher des informations avec printf

La commande printf est un « grand classique » qu'on retrouve dans plusieurs langages de programmation (C, PHP pour ne citer que ceux-là). L'idée de cette commande est de réaliser un affichage formaté (c'est le « f » de printf). Cette commande remplace souvent avantageusement la commande echo bien plus limitée. Pour ce qui est de son utilisation, printf attend une chaîne de format précisant l'allure de l'affichage, suivie d'un nombre variable d'arguments. Par exemple :

 
Sélectionnez
$ printf "%d est un nombre pseudo-aleatoire\n" $RANDOM
14234 est un nombre pseudoaléatoire
$

Ce premier exemple peut être traduit en français par : je souhaite afficher un entier (%d) en base 10, suivi de la phrase « est un nombre pseudo-aléatoire », suivie d'un saut de ligne (\n). Dans l'exemple suivant la chaîne de format est suivie par 2 arguments :

 
Sélectionnez
$ printf "En voici 2 autres : %d et %d\n" $RANDOM $RANDOM
En voici 2 autres : 23943 et 83442
$

On comprend donc qu'à chaque %d contenu dans la chaîne de format doit correspondre un argument. printf reconnaît un certain nombre de type de données, entre autres :

  • %d pour afficher un entier en base décimale (on peut également utiliser %o pour la base octale et %x pour la base hexadécimale) ;
  • %f pour afficher un nombre à virgule flottante ;
  • %s pour afficher une chaîne ;

Par ailleurs, chacun de ces types de données accepte un certain nombre de modificateurs.

En voici quelques-uns :

 
Sélectionnez
$ printf "==[%010d]==\n" $RANDOM
==[0000007052]==
$

pour afficher un entier sur 10 caractères comblés avec des zéros si nécessaire.

 
Sélectionnez
$ printf "==[%-20s]==\n" $USER
==[lozano ]==
$

pour une chaîne produite sur 20 caractères alignée à gauche (signe « - »). D'autres exemples devraient vous venir à l'esprit après avoir lu le « fantastique manuel ». 

3-4-2. Substitution de commande

La substitution de commande est un mécanisme permettant d'exploiter la sortie d'une commande dans l'appel d'une autre commande. La syntaxe permettant de réaliser la substitution est $(…). Pour comprendre comment cela se passe, soit la commande suivante, affichant le nombre de lignes du fichier fichier.dat :

 
Sélectionnez
 wc -l fichier.dat
3 fichier.dat
$

On se débarrasse pour l'exemple du nom de fichier :

 
Sélectionnez
$ wc -l fichier.dat | cut -f1 -d' '
3
$

On peut également s'en débarrasser en utilisant une redirection :

 
Sélectionnez
$ wc -l < fichier.dat
3
$

Si on voulait maintenant utiliser cette valeur dans une commande :

 
Sélectionnez
$ echo Il y a $(wc -l < fichier.dat) musiciens
Il y a 3 musiciens
$

Ici, dans un premier lieu, ce qui se trouve entre les caractères $(…) est remplacé par ce qu'affiche la commande wc -l …, c'est-à-dire 3, puis la commande echo réalise l'affichage. Avec printf on écrira :

 
Sélectionnez
$ printf 'Il y a %d musiciens' "$(wc -l < fichier.dat)"
$

Un autre exemple : sachant que la commande date affiche la date sous un format que l'on peut définir :

 
Sélectionnez
$ date +%h%d
Dec15
$

Il est possible de sauvegarder un fichier comme suit :

 
Sélectionnez
$ cp source.cc source.cc.$(date +%h%d)
$

La commande cp ci-dessus copie le fichier source.cc en un fichier dont le nom est source.cc. concaténé avec ce que renvoie la commande date.

 
Sélectionnez
$ ls source.cc*
source.cc source.cc.Dec15
$

Il existe une autre syntaxe pour la substitution de commande. En lieu et place de la forme $(commande), certains vieux shells ne disposent que de la syntaxe utilisant le backquote (‘) :

  • commande

Qu'on se le dise…

3-4-3. La structure for de bash

Le shell bash propose une structure de contrôle nommée for que l'on peut traduire par « pour chaque », la syntaxe en est la suivante :

  • for variable in liste ; do com1 ; com2 ; … ; done

On peut donc écrire quelque chose de la forme :

 
Sélectionnez
$ for F in *.fig ; do echo "$F.tmp" ; done
arborescence.fig.tmp
disques.fig.tmp
flux.fig.tmp
pipes.fig.tmp
$

On affiche ici, pour F prenant les valeurs de l'expansion de *.fig, la variable F suivie de la chaîne .tmp, ce qui a, je vous l'accorde, peu d'intérêt.

Notez ici les guillemets dans la syntaxe echo "$F.tmp" qui a pour but de ne pas considérer $F.tmp comme une liste si jamais il existe un fichier dont le nom contient un espace.

On peut imaginer un autre exemple, qui utilise l'expansion de commande :

 
Sélectionnez
$ for F in $(find . -name '*.jpg') ; do xzgv "$F" & ; done
$

qui lance xzgv (un visualiseur d'image) en tâche de fond, pour chaque fichier portant l'extension jpg dans le répertoire courant et ses sous-répertoires.

L'exemple ci-dessus possède une limitation : il ne fonctionne pas si le nom des fichiers portant l'extension jpg contient un espace (ou un saut de ligne, ce qui est plutôt rare…). Nous vous renvoyons au paragraphe sur la variable IFSInput field separator pour pallier ce problème.

3-4-4. Revenons à nos moutons

« Nos moutons », c'est notre problème de transformation de noms de fichiers majuscules en minuscules. La commande tr (translate) a la capacité de transformer une chaîne de caractères :

 
Sélectionnez
$ echo SALUT | tr A-Z a-z
salut
$

Donc pour renommer nos fichiers on peut imaginer la commande suivante, qui rassemble les concepts vus dans ce paragraphe :

 
Sélectionnez
$ for F in $(find . -name '*JPG') ; do Entrée
et?> mv "$F" "$(echo $F | tr A-Z a-z)"; done
$

Ce qui peut se traduire en français par : tous les fichiers finissant par JPG doivent être renommés en utilisant le résultat de l'affichage du nom original filtré par tr (c'est-à-dire en minuscule).

Cette commande présente l'inconvénient de ne pas fonctionner si les images JPG en question se trouvent dans des sous-répertoires dont les noms contiennent des majuscules. Elle possède en outre les mêmes limitations que l'exemple précédent (noms de fichier contenant un espace ou un saut de ligne). Par ailleurs, il est bon de savoir que ce genre de tâches (copie/déplacement de fichiers en salve) peut être réalisé de manière sûre (en limitant les risques d'écrasement de fichiers) grâce à l'utilitaire mmv disponible dans toutes les bonnes crèmeries.

Dans la commande précédente, l'utilisateur a appuyé sur la touche Image non disponible avant que la commande find ne soit complète. Le shell affiche alors un autre prompt qui se distingue du prompt habituel, pour informer l'utilisateur que la commande est incomplète.
La manière d'afficher ce prompt est définie par la variable PS2Le prompt. Dans la suite de ce document, nous n'indiquerons plus la pression sur la touche Image non disponible dans les exemples. 

3-5. grep et la notion d'expressions régulières

La commande grep est une commande « célèbre » d'unix et permet d'afficher les lignes d'un flux correspondant à un motif donné. Par exemple :

 
Sélectionnez
$ grep Hendrix fichier.dat
Jimi Hendrix 1970
$

ou :

 
Sélectionnez
$ grep Jim fichier.dat
Jimi Hendrix 1970
Jim Morrison 1971
$

Les motifs en question (Hendrix et Jim) dans les deux exemples précédents se nomment en jargon unix(50) une expression régulière (ou une expression rationnelle(51)) (regular expression parfois abrégé en regexp). L'étude de la théorie des expressions régulières pourrait faire l'objet d'un document de la taille de ce guide de survie. Voici cependant sous forme d'un tableau à quoi correspondent quelques-uns des motifs d'une expression régulière.

. désigne n'importe quel caractère B
* zéro ou plusieurs fois l'élément précédent B
? zéro ou une fois l'élément précédent E
+ une ou plusieurs fois l'élément précédent E
^ correspond au début de la ligne B
$ correspond à la fin de la ligne B
[abc] un caractère parmi abc B
[^abc] tout caractère sauf a, b ou c B
{n} exactement n fois l'élément précédent E
{n,m} au moins n fois et au plus m fois l'élément précédent(52). E

La version de grep utilisée pour l'exemple est celle de chez gnu. Cette commande comprend trois ensembles d'expressions régulières (basique, étendue et Perl). Dans le tableau précédent les deux premiers ensembles sont indiqués respectivement par B et E dans la colonne de droite.

Voyons quelles sont les applications de ces motifs. La commande :

 
Sélectionnez
$ grep '197.$' fichier.dat
Jimi Hendrix 1970
Jim Morrison 1971
$

récupère les lignes finissant par la chaîne « 197 » suivie d'un caractère quel qu'il soit.

Notez qu'il est sage de « quoter » (entourer par des apostrophes) le motif, car beaucoup de caractères composant les expressions régulières sont des caractères spéciaux pour le shell.

La commande :

 
Sélectionnez
$ grep '^Ji' fichier.dat
Jimi Hendrix 1970
Jim Morrison 1971
$

récupère les lignes commençant par la chaîne « Ji ». La commande :

 
Sélectionnez
$ grep '^J.*1970' fichier.dat
Jimi Hendrix 1970
$

récupère les lignes commençant par « J » et contenant « 1970 ». La commande :

 
Sélectionnez
$ grep -E 'Jimi?' fichier.dat
Jimi Hendrix 1970
Jim Morrison 1971
$

récupère les lignes contenant « Jimi » ou « Jim ». Il est ici nécessaire d'utiliser l'option -E (extended regexp) pour pouvoir utiliser le caractère ?. Parmi les options intéressantes de grep, en voici trois :

  • l'option -w (word) permet de restreindre le résultat de la correspondance à un mot entier :

     
    Sélectionnez
    $ grep Jim fichier.dat
    Jimi Hendrix 1970
    Jim Morrison 1971
    $

    Mais :

     
    Sélectionnez
    $ grep -w Jim fichier.dat
    Jim Morrison 1971
    $

    Pour le Gnu grep qui dispose de l'option -w, un « mot » est défini comme un ensemble de caractères parmi les lettres, les chiffres et le caractère souligné « _ » (underscore).

  • l'option -i (ignore case) permet d'ignorer la casse (minuscule ou majuscule) dans la correspondance avec le motif :

     
    Sélectionnez
    $ grep -i jimi fichier.dat
    Jimi Hendrix 1970
    $
  • l'option -v (revert match) inverse le sens de la correspondance et n'affiche que les lignes qui ne correspondent pas à l'expression régulière :
 
Sélectionnez
$ grep -vi jim fichier.dat
Janis Joplin 1969
$

La commande grep a été utilisée pour les exemples avec un fichier comme argument, mais elle peut bien évidemment faire la correspondance sur son flux d'entrée et être composée avec des tubes. Par exemple, la commande :

 
Sélectionnez
$ ps -ef | grep '^lozano'
lozano 11396 1 0 14:53 ? 00:00:00 xterm -ls
lozano 11398 11396 0 14:53 pts/2 00:00:00 -bash
lozano 11512 11398 0 14:58 pts/2 00:00:00 ps -ef
lozano 11513 11398 0 14:58 pts/2 00:00:00 grep lozano
...
$

filtre le résultat de la commande ps en ne renvoyant que les lignes commençant par la chaîne lozano. Ce qui permet d'avoir la liste des processus dont lozano est le propriétaire. Notez enfin que la commande ps -fu lozano aurait donné un résultat identique… 

3-6. awk

On peut voir awk(53) comme un filtre permettant d'effectuer des modifications sur les lignes d'un flux ; ces lignes étant sélectionnées par l'intermédiaire d'une expression régulière (dans le même esprit que grep) ou d'une condition quelconque. Cependant awk dispose d'un langage de programmation spécial (dont la syntaxe pourrait se rapprocher de celle du C) permettant de manipuler et modifier les lignes sélectionnées comme un ensemble de champs (à l'instar de cut). La syntaxe générale d'un programme awk est une suite de règles définies comme un couple de motifs et d'actions :

  • les motifs permettent de sélectionner des lignes dans le flux et sont :
  • soit des expressions régulières et doivent être délimités par des / (par exemple /abc/) ;
  • soit des expressions simples (égalité, inégalité…) ;
  • les actions sont exécutées pour chaque motif et sont délimitées par des { et } (par exemple dans l'expression {print "bonjour\n"}).

Ces caractères ayant une signification particulière pour le shell, il faut les protégerIntroduction à l'expansion par des cotes '.

Voici un petit programme awk :

 
Sélectionnez
$ awk '{print $1,$3}' fichier.dat
Jimi 1970
Jim 1971
Janis 1969
$

Dans cet exemple, on sélectionne toutes les lignes (pas de motif spécifié) et on affiche les champs numéro 1 ($1) et 3 ($3) - correspondant aux prénoms et dates - de chacune de ces lignes. awk délimite les champs par un nombre quelconque d'espaces ou tabulations(54). On peut utiliser une expression régulière comme ceci :

 
Sélectionnez
$ awk '/^Jim/{print $1,$3}' fichier.dat
Jimi 1970
Jim 1971
$

où l'expression régulière « ˆJim » spécifie « ligne commençant par Jim ». Voici un autre exemple :

 
Sélectionnez
$ awk '$3==1970{print "En "$3" "$2"..."}' fichier.dat
En 1970 Hendrix...
$

Ici on a sélectionné les lignes à l'aide d'une expression simple : un test d'égalité sur le 3e champ. On peut en outre effectuer un appariement de motif uniquement sur un champ particulier, grâce à l'opérateur ~ de awk :

 
Sélectionnez
$ awk '$2 ~ /lin$/ {print "Cette chere "$1"..."}' fichier.dat
Cette chere Janis...
$

L'opérateur ~ permet en effet de filtrer le flux avec une correspondance sur un champ (ici le 2e doit finir par « lin »).

On peut utiliser des variables en leur donnant un nom. Leur manipulation (affectation, comparaison…) s'apparente à celle du langage C. On peut par exemple faire la moyenne des années comme suit :

 
Sélectionnez
$ awk '{s+=$3} END{print "moyenne : "s/NR}' fichier.dat
moyenne : 1970
$

on a ajouté pour chaque ligne la valeur du 3e champ à la variable s. Et dans la clause END (qui n'est exécutée qu'à la fin), on divise par NR le nombre d'enregistrements (lignes) du flux (number of record). La commande print peut également être remplacée par la commande printf.

awk dispose d'un langage complet, possédant des structures de contrôle (boucle for, boucle while, if…), un ensemble d'outils pour le traitement des chaînes de caractères, ainsi que des fonctions mathématiques (racine carré, log, fonctions trigonométriques, etc.).

3-7. sed

sed (pour stream editor) est, comme son nom l'indique, un éditeur de flux. Il permet de faire des transformations sur des chaînes de caractères. Nous donnerons un exemple simple qui consiste à remplacer une chaîne de caractères dans un fichier. La syntaxe est alors :

  • sed 's/recherche/remplace/' fichier

ou

  • sed 's/recherche/remplace/' < fichier

recherche est la chaîne recherchée et remplace la chaîne qui servira de remplacement.

Par exemple, pour changer le nom d'une variable dans un source C :

 
Sélectionnez
$ sed 's/iterateur/compteur/g' < fichier.c > nouveau.c
$

Ici sed lit le contenu de fichier.c et réalise le remplacement (commande s pour substitute) de la chaîne « iterateur » par la chaîne « compteur ». La commande g (global) assure que la chaîne sera remplacée plusieurs fois par ligne le cas échéant.

Enfin notons que, comme awk, sed renvoie son résultat sur le flux de sortie.

En imaginant que l'on veuille faire la même opération sur plusieurs fichiers, on peut utiliser la commande for vue précédemment :

 
Sélectionnez
$ for F in *.c ; do
et?> sed 's/iterateur/compteur/g' < "$F" > tmp &&
et?> mv -f tmp "$F"; done
$

La commande s de sed dispose également de « registres » qui permettent de réutiliser des parties de la chaîne qui correspondent aux motifs spécifiés. Considérons l'exemple suivant : à partir de notre célèbre fichier fichier.dat contenant :

 
Sélectionnez
fichier.dat
Jimi Hendrix 1970
Jim Morrison 1971
Janis Joplin 1969

on veut construire la liste :

 
Sélectionnez
Hen1970
Mor1971
Jop1969

Soit l'expression régulière suivante :

 
Sélectionnez
^[A-Za-z]* [A-Z][a-z]{2}[a-z]* [0-9]{4}

cette expression est capable de reconnaître :

  • un début de ligne suivi d'une suite de caractères en minuscules ou en majuscules ([A-Za-z]*) ;
  • suivie d'un espace ;
  • suivi d'une majuscule (([A-Z]), suivie de deux minuscules ([a-z]{2}), suivies d'un nombre quelconque de lettres en minuscules ([a-z]*) ;
  • suivi d'un espace ;
  • suivi d'exactement quatre chiffres ([0-9]{4}).

De manière à utiliser cette expression avec sed, il est nécessaire d'utiliser l'option -r forçant l'utilisation des expressions régulières étendues (extended regexp) :

 
Sélectionnez
$ sed -r 's/^[A-Za-z]* [A-Z][a-z]{2}[a-z]* [0-9]{4}/xxx/' fichier.dat
xxx
xxx
xxx
$

Toutes les lignes correspondent à l'expression régulière, elles sont donc remplacées par « xxx ». De manière à réutiliser des parties de l'expression régulière dans le remplacement, on les délimite par les caractères ( et ), les registres ainsi formés sont nommés \1, \2, etc. Dans notre exemple nous allons récupérer les trois premières lettres du nom et l'année :

 
Sélectionnez
$ sed -r 's/^[A-Za-z]* ([A-Z][a-z]{2})[a-z]* ([0-9]{4})/\1\2/' \
fichier.dat
Hen1970
Mor1971
Jop1969
$

Notez la position des couples de caractères ( et ). Le registre \1 contient le nom, et le registre \2 contient l'année.

Sans la version gnu de sed qui propose l'option -r, on doit utiliser les caractères \( et \) pour délimiter les motifs à réutiliser. D'autre part on utilise l'expression régulière pour préciser qu'un motif est répété n fois doit être \{n\} et non {n}. Ce qui donne :

 
Sélectionnez
^[A-Za-z]* \([A-Z][a-z]\{2\}\)[a-z]* \([0-9]\{4\}\)

pour la partie gauche de la commande s…

Notons, juste pour rire, que la solution à ce problème en utilisant awk est la suivante :

 
Sélectionnez
$ awk '{print substr($2,0,3)$3}' fichier.dat
Hen1970
Mor1971
Jop1969
$

Mais gardons à l'esprit que cet exemple vise surtout à illustrer la puissance des expressions régulières.

3-8. Études de cas

Nous vous présentons dans cette section trois « études de cas » mettant en application la plupart des outils standard d'unix.

3-8-1. Manipuler la liste des utilisateurs

Sur un système unix, on peut obtenir la liste des utilisateurs potentiels du système grâce à la commande getent passwd(55). Cette commande renvoie le fichier contenant les caractéristiques de chaque utilisateur :

 
Sélectionnez
$ getent passwd
merle_g:x:1321:1300:MERLE Gerard/home/4annee/merle_g:/bin/tcsh
talji_y:x:966:900:TALJI Yacine:/home/1/talji_y:/bin/tcsh
maurin_r:x:945:900:MAURIN Raphaelle:/home/1/maurin_r:/bin/tcsh
sergen_c:x:1415:1400:SERGENT Chris:/home/5/sergen_c:/bin/tcsh
arnaud_l:x:1416:1400:ARNAUD Lionel:/home/5/arnaud_l:/bin/tcsh
lepeti_c:x:1408:1400:LEPETIT Claire:/home/5/lepeti_c:/bin/tcsh
... etc ...
$

Le flux renvoyé a la structure suivante, de gauche à droite :

  • le login_name de l'utilisateur ;
  • un « x » pour le champ mot de passe ;
  • le numéro (uid pour user identifier) de l'utilisateur ;
  • le numéro (gid pour group identifier) du groupe de l'utilisateur ;
  • son nom en clair ;
  • son répertoire racine ;
  • son shell de connexion.

On peut noter que ces champs sont séparés par des « : ». Le nombre d'utilisateurs potentiels est donc le nombre de lignes renvoyées par la commande getent :

 
Sélectionnez
$ getent passwd | wc -l
277
$

Pour obtenir la liste des utilisateurs dont le groupe principal est un groupe particulier, par exemple le groupe numéro 1300, on peut agir comme suit :

 
Sélectionnez
$ getent passwd | grep -w 1300 | cut -d':' -f5
MERLE Geraldine
ESCOFFIER Carole
GACON-LOCATELLI Anne
BOYAUD Xavier
SIGUIER Vincent
LASNIER Christophe
PEROCHE Jerome
... etc ...
$

on fait une recherche de toutes les lignes contenant la chaîne 1300 (ce qui n'est pas exactement ce que l'on cherche, je vous l'accorde, mais lisez la suite), et pour ces lignes, on affiche le 5e champ (en précisant que le séparateur est « : »). Pour classer par ordre alphabétique, il suffit de rajouter un tube avec sort :

 
Sélectionnez
$ getent passwd | grep -w 1300 | cut -d':' -f5 | sort
ALBERT-GONDRAND Johanne
BARNEOUD Julien
BAROQUE Philippe
ARTOS Romain
...
$

Enfin si on voulait afficher le résultat sous la forme prénom-nom, on pourrait rajouter un « petit » awk :

 
Sélectionnez
$ getent passwd | grep 1300 | cut -d':' -f5 | sort |
et?> awk '{print $2" "$1}'
Johanne ALBERT-GONDRAND
Julien BARNEOUD
Philippe BAROQUE
Romain BARTOS
...
$

Les lecteurs attentifs auront sans doute noté que le filtre grep 1300 pourra sélectionner une ligne contenant la chaîne 1300, même s'il ne s'agit pas du numéro de groupe. Pour remédier à ce problème on pourrait utiliser à la place du grep 1300 :

 
Sélectionnez
gawk -F: '$4==1300{print $5}'

qui aurait tout de même quelque peu surchargé notre exemple à vocation pédagogique (l'option F indique à awk le séparateur de champ des données en entrée, la variable OFS pour output field separator)… 

3-8-2. Envoyer des mails

Pour faire ce qu'on appelle du mailing (envoyer le même message à plusieurs utilisateurs), on peut créer deux fichiers :

  • destinataires contenant les adresses électroniques des destinataires, et :
  • message contenant le message à envoyer.

On peut créer destinataires manuellement ; on peut également le créer automatiquement, par exemple les destinataires « groupe 1300 » pourraient être construits comme suit :

 
Sélectionnez
$ getent passwd | awk -F: '$4 == 1300' { print $1 }' > destinataires
$

L'envoi des messages est réalisé grâce à une boucle for :

 
Sélectionnez
$ for U in $(cat destinataires); do\
et?> mail -s "salut" $U < messages
et?> done
$

Si la commande mail de votre système est capable d'envoyer des messages à plusieurs utilisateurs à la fois, vous pourriez également écrire :

 
Sélectionnez
$ mail -s "salut" $(getent passwd | awk -F: '$4 == 1300'{print $1})
$
 

3-8-3. Estimer l'occupation de certains fichiers

Pour estimer la taille d'un certain type de fichier (comme les images, les fichiers PostScript…) on peut procéder comme suit : tout d'abord rechercher ces fichiers avec la commande find :

 
Sélectionnez
$ find ~/ -name "*.ps"
/home/equipe/lozano/LaTeX/test/test.ps
/home/equipe/lozano/LaTeX/local/local.ps
/home/equipe/lozano/LaTeX/local/local.2up.ps
...
$

qui donne la liste de tous les fichiers PostScript (extension ps) dans la zone de l'utilisateur.

La version gnu de find permet également d'afficher les caractéristiques des fichiers listés grâce à une option tout à fait analogue au printf du C :

 
Sélectionnez
$ find ~/ -name "*.ps" -printf "%p %k\n"
/home/equipe/lozano/LaTeX/test/test.ps 6
/home/equipe/lozano/LaTeX/local/local.ps 1850
/home/equipe/lozano/LaTeX/local/local.2up.ps 1880
...
$

la chaîne de format du printf utilise %p pour le nom du fichier, et %k pour sa taille arrondie en kilo-octets (voir l'aide de la commande find). Grâce à un tube avec awk on peut afficher les fichiers dont la taille est supérieure à 1 mégaoctet :

 
Sélectionnez
$ find ~/ -name "*.ps" -printf "%p %k\n" |
et?> awk '$2 > 1024 {print $1" "$2}'
/home/equipe/lozano/LaTeX/local/local.ps 1850
/home/equipe/lozano/LaTeX/local/local.2up.ps 1881
/home/equipe/lozano/LaTeX/util/local.ps 1855
/home/equipe/lozano/install/lettre/doc/letdoc2.ps 1385
...
$

On peut également obtenir la taille totale de ces fichiers :

 
Sélectionnez
$ find ~/ -name "*.ps" -printf "%k\n" |
et?> awk '{taille+=$1}END{print taille}'
52202
$

Pour finir si on voulait effacer tous ces fichiers, ou seulement ceux dont la taille est supérieure à un seuil donné, il suffirait de procéder comme suit :

 
Sélectionnez
$ find ~/ -name "*.ps" | xargs rm -f
$

Sans argument particulier, find affiche la liste des fichiers répondant au critère. La commande xargs passe en argument de la commande qui la suit (ici rm -f) le flux qu'elle reçoit en entrée. Donc ici on va exécuter rm -f avec comme argument tous les fichiers renvoyés par la commande find.

Voici un autre exemple d'utilisation de la commande xargs : supposons qu'on veuille chercher dans quel fichier include (les fichiers entête du langage C) est défini l'appel système gethostbyname(56). Pour ce faire on va chercher tous les fichiers dont l'extension est .h du répertoire /usr/include et de ses sous-répertoires :

 
Sélectionnez
$ find /usr/include -name "*.h"
/usr/include/utempter.h
/usr/include/apm.h
/usr/include/ansidecl.h
/usr/include/bfd.h
...
$

Pour l'ensemble de ces fichiers on va utiliser grep pour chercher la chaîne de caractères gethostbyname :

 
Sélectionnez
$ find /usr/include -name "*.h" | xargs grep -w gethostbyname
/usr/include/netdb.h:extern struct hostent *gethostbyname __P
((__const char *__name));
/usr/include/tcpd.h:#define gethostbyname fix_gethostbyname
$

Cette idée peut être utilisée pour chercher une chaîne dans un ensemble de fichiers.

Une autre forme juste pour confirmer l'épigraphe de la préface :

 
Sélectionnez
$ grep --include='*.h' -rw gethostbyname /usr/include
$

demande à grep de faire une recherche récursive (-r) dans le répertoire spécifié en dernier argument (/usr/include/) en n'examinant que les fichiers dont le nom finit par .h (ceci est une « exclusivité » gnu)…

3-9. Conclusion

Vous êtes maintenant armés pour étudier les chapitres suivants respectivement consacrés à la communication via le réseau, au développement de programmes et la configuration de son environnement. Le chapitre traitant du développement inclut une partie non négligeable présentant le shell en tant que langage de programmation en mode non interactif. De manière générale le présent chapitre donne un aperçu de la « philosophie » d'unix et doit vous permettre d'appréhender différents outils et logiciels que vous serez susceptible de rencontrer.


précédentsommairesuivant
Encore un jeu de mots d'informaticien : le remplaçant de l'ancêtre more est less, ah-a ah-a, assez ri… J'apprends à l'instant que la nouvelle évolution de most s'appelle most, arf, arf, arf… hum, un peu de sérieux.
gzip est devenu le standard de facto de compression sous unix ; malgré tout, on ne trouve sous certains systèmes que la commande compress qui suit peu ou prou la même syntaxe que gzip. Notons également que gzip sera à moyen terme probablement supplanté par bzip2 qui permet d'obtenir un meilleur taux de compression.
Et plus généralement dans le domaine de l'étude des langages informatiques.
J'utilise pour ma part la première forme, ne pas taper svp…
Dans cette expression, n ou m peuvent être omis.
Du nom de ses auteurs initiaux en 1977, Alfred V. Aho, Peter J. Weinberger, and Brian W. Kernighan
Comportement qui peut être changé par l'option -F.
Sur votre système il peut s'agir d'une autre commande…
Encore un exemple farfelu lorsqu'on sait que man gethostbyname donne l'information recherchée.

Licence Art libre http://artlibre.org. Par contre, les logos Developpez.com, en-tête, pied de page, css, et look et feel de l'article sont Copyright © 2013 Developpez.com.