6. Chapitre 6 - Se mettre à l'aise !▲
On login (subject to the -noprofile option): if /etc/profile exists, source it. if ~/.bash_profile exists, source it, On exit: if ~/.bash_logout exists, source it. man bash. |
Développer un projet c'est aussi être dans un environnement agréable et correspondant à ses propres besoins. Ce chapitre a pour but de présenter la configuration de l'environnement de travail pour que le programmeur puisse se focaliser sur son travail. Ce chapitre n'est pas un inventaire de ce que l'on peut configurer sous unix, mais consiste en une présentation des mécanismes de configuration proprement dits. Nous présentons donc ici, la configuration du shell, l'utilisation d'emacs et vi , le principe de la configuration d'un environnement graphique, ainsi que l'installation de logiciels pour un utilisateur sans privilège. Cette dernière section est terminée par une présentation de la gestion des paquets Debian.
6-1. Avec le shell▲
Le shell est l'environnement de travail de base sous unix. Grâce au shell on peut dialoguer avec le système par le biais de commandes, de scripts, en lançant des logiciels, etc. Il est donc important que cet environnement soit configuré le mieux possible par rapport au besoin de l'utilisateur. La plupart des configurations effectuées au niveau du shell se font :
- soit à l'aide de variables dites variables d'environnementRudiments sur les variables d'environnement ;
- soit en positionnement des variables propres au shell utilisé.
Les possibilités de configuration présentées dans cette section ne prennent leur intérêt que couplées avec les fichiers de démarrageSauvegarder ses configurations grâce aux fichiers de démarrage : la configuration d'un environnement utilisateur passe par le positionnement de variables dans ces fichiers de démarrage de manière à rendre actif l'environnement personnalisé à chaque connexion.
Les variables d'environnement sont des variables qui sont « exportées » - c'est-à-dire transmises - aux processusProcessus fils du shell, par l'une des syntaxes suivantes :
Voyons sur un exemple comment sont exportées ces variables en considérant le script suivant :
#!/bin/bash
echo X
=
$X
echo Y
=
$Y
$ X=4
$ export Y=5
$ ./testexport.sh
X=
Y=5
$
on constate ici que le script testexport.sh « connaît » la valeur de la variable Y, mais X, elle, est inconnue, car uniquement définie pour le shell.
6-1-1. Le prompt▲
On peut changer l'allure du prompt en modifiant le contenu de la variable PS1.
Par exemple :
$ PS1="vasyfaitpter# "
vasyfaitpter# date
Wed Jun 7 11:55:21 CEST 2000
vasyfaitpter#
On peut avoir un prompt un peu plus évolué dans lequel il est possible d'ajouter entre autres (ce qui suit est spécifique à bash) :
- le nom de l'utilisateur : \u (user) ;
- le nom de la machine : \h (host name) ;
- le répertoire de travail : \w ou \W pour une forme abrégée (working directory) ;
- la date et l'heure : \d et \t (date et time).
Nous avons un petit faible pour le prompt suivant :
$ PS1="\u@\h:\w>"
lozano@coltrane:~/tcqvatvs/guide>
ou plus succinctement :
$ PS1="\h\w>"
coltrane~/tcqvatvs/guide>
Les shells utilisent également un prompt particulier pour indiquer qu'une commande n'est pas complète bien que l'utilisateur ait pressé la touche . Ce prompt s'affiche sous bash en fonction de la valeur de la variable PS2. Par défaut cette variable contient la chaîne « > », on peut y mettre par exemple :
$ PS2="et?> "
$
pour attirer l'attention. Ainsi :
$ for x in 1 2 3 ; do
et?> echo $[x+1]
et?> done
2
3
4
$
Les autres shells disposent également de variables permettant de spécifier l'allure du prompt ; la syntaxe est légèrement différente, mais l'idée générale est la même.
6-1-2. Historique des commandes▲
Comme nous avons pu le noter, les shells d'unix proposent généralement un mécanisme d'historique permettant aux vaillants utilisateurs de rappeler les commandes déjà saisies, pour éventuellement les corriger ou simplement les réexécuter. L'utilisateur peut compulser cet historique avec la commande history :
$ history
... ...
510 xdvi guide-unix.dvi &
511 pdflatex guide-unix
512 acroread guide-unix.pdf &
513 xfig figs/lien_symbolique.fig&
514 history
$
Par défaut le shell bash stocke cet historique, à chaque fois qu'on quitte un shell, dans un fichier dont le nom est stocké dans la variable HISTFILE. Par exemple sur la machine de votre serviteur :
$ echo $HISTFILE
/home0/vincent/.bash_history
$
Deux autres variables sont bonnes à connaître :
- HISTFILESIZE le nombre de lignes à mémoriser pour l'historique ;
-
HISTCONTROL qu'on peut positionner à la valeur :
- ignoredups pour ne pas stocker dans l'historique deux commandes identiques ;
- ignorespace pour ne pas stocker les lignes commençant par un espace ;
- ignoreboth pour cumuler les deux effets précédents.
Pour info, sur mon système :
$ echo $HISTFILESIZE $HISTCONTROL
500 ignoreboth
$
6-1-3. Alias et fonctions▲
Il est souvent intéressant d'utiliser les alias pour créer ce qu'on pourrait appeler des « raccourcis » de commandes. Par exemple, au lieu d'écrire :
$ telnet -l lozano coltrane.freejazz.org
Trying xx.xx.xx.xx...
Connected to coltrane.freejazz.org
Escape character is '^]'.
...
$
On peut définir un alias :
$ alias trane='telnet -l lozano coltrane.freejazz.org'
$ trane
Trying xx.xx.xx.xx...
Connected to coltrane.freejazz.org.
Escape character is '^]'.
$
Contrairement aux alias de tcsh, ceux de bash « se contentent » d'effectuer le remplacement de l'alias par sa définition. Mais cette définition ne peut contenir de référence aux arguments de la ligne de commande. Il faut pour cela utiliser des fonctionsFonctions de bash.
Voici un exemple simple de fonction : supposons que l'on se connecte régulièrement sur la machine ayler.freejazz.org, mais sous des utilisateurs différents. On pourrait avoir l'idée de génie d'écrire :
function sshayler()
{
${1?:="donnez moi un login plize..."}
ssh -X -l $1 ayler.freejazz.org
}
Une fois cette fonction stockée dans un fichier de démarrageSauvegarder ses configurations grâce aux fichiers de démarrage, on pourra simplement taper :
sshayler vincent
$
pour se connecter en tant qu'utilisateur vincent sur ayler.freejazz.org, quelle joie… Notons enfin qu'il y a un ordre de priorité dans l'exécution des commandes, alias et autres fonctions ; cet ordre est le suivant :
- les alias ;
- les fonctions ;
- les commandes internes ;
- les commandes externes.
Ainsi, si par exemple on définit un alias :
$ alias xdvi='xdvi -keep'
$
Alors la commande :
$ xdvi bidule.dvi &
$
fera d'abord appel à l'alias qui lui, fera appel à la commande externe. L'option -a de la commande type peut donner des informations à ce sujet :
$ type -a xdvi
xdvi is aliased to `xdvi -keep' <--------------------------- alias
xdvi is /usr/bin/xdvi <-------------------------- commande externe
$
6-1-4. Environnement de développement▲
Lorsqu'on développe des applications il arrive qu'on veuille les stocker dans un sous-répertoire du répertoire privé tel que, par exemple, ~/bin. Sans modification particulière de l'environnement les programmes stockés dans ce répertoire ne pourront être exécutés sans spécifier le nom complet du répertoire de stockage :
- ˜/bin/mon-exécutable
Pour remédier à cet inconvénient, on peut modifier la variable d'environnement PATH. Cette variable contient une liste de répertoires séparés par des « : » dans lesquels le shell va chercher les exécutables appelés en ligne de commande. Par exemple, sur notre système :
$ echo $PATH
/usr/local/Acrobat5/bin:/usr/local/bin:
/bin:/usr/bin:/usr/X11R6/bin
$
Par conséquent, pour rajouter ~/bin dans cette liste, on peut écrire :
$ export PATH=~/bin:$PATH
$
Ceci permet d'ajouter en début de liste notre répertoire de stockage des exécutables « maison ». Lorsque ces exécutables sont liés dynamiquement avec des bibliothèques « maison », on pourra stocker ces bibliothèques dans un répertoire, par exemple ~/lib ; et pour faire en sorte que leur chargement se déroule correctement il faudra mettre à jour la variable d'environnement LD_LIBRARY_PATH :
$ export LD_LIBRARY_PATH=~/lib:$LD_LIBRARY_PATH
$
On pourra aussi se reporter au paragraphe 5.4.4Bibliothèques pour plus d'informations au sujet des bibliothèques dynamiques.
6-1-5. Interaction avec les logiciels▲
Certains logiciels font appel à des variables d'environnement pour fonctionner. On ne peut évidemment pas dresser une liste exhaustive de ces variables. Voici cependant quelques exemples qui permettront de comprendre le mécanisme global : beaucoup de logiciels sont conçus pour avoir un comportement par défaut que l'on peut surcharger en positionnant une variable d'environnement.
-
certains programmes utilisent la variable EDITOR au moment de lancer l'édition d'un texte ; ils supposent généralement que l'éditeur par défaut est vi ; si pour une raison ou une autre vous désirez utiliser un autre éditeur :
-
$ export EDITOR=mon_éditeur
$
fera l'affaire ;
-
$ export EDITOR=mon_éditeur
-
la variable TERM indique au système le type de terminal utilisé. La valeur « passepartout » est le vt100 compatible avec la plupart des terminaux et qui suffit à la plupart des applications. On pourra donc écrire :
Sélectionnez$ export TERM=vt100 $ reset ... $
- en cas de liaison difficile avec une machine distante possédant un système n'identifiant pas votre type de terminal.
- la variable PAGER définit le programme chargé d'afficher les pages de manuelLes pages de manuel avec la commande man ;
- …
En règle générale, les pages de manuel contiennent une rubrique baptisée « Environnement » qui décrit les variables d'environnement ayant une influence sur le programme en question.
6-1-6. Sauvegarder ses configurations grâce aux fichiers de démarrage▲
Lorsque le système lance un processus de shell, ce dernier va lire - suivant sa famille sh ou csh - dans un ordre défini, un certain nombre de fichiers pouvant contenir des commandes ou des initialisations de variables d'environnement. Ces fichiers sont appelés fichiers de démarrage et portent généralement le doux nom, de login, profile, et autre monshellrc… Pour comprendre le fonctionnement des fichiers de démarrage, il faut d'abord distinguer les trois types de lancement d'un shell :
- login shell : ou shell de connexion, il est lancé lors de la connexion (ou login) sur le système ;
- non login interactive shell : il s'agit d'un shell lancé autrement que par une procédure de connexion, par exemple par l'intermédiaire d'une fenêtre xterm ;
- non interactive : shell lancé pour interpréter un fichier de commande ;
Dans le cas du shell bash, les fichiers lus sont les suivants :
- login shell : ~/.bash_profile ;
- non login shell : ~/.bashrc ;
- non interactif : le fichier dont le nom est dans la variable ENV.
Voici un exemple de configuration classique des fichiers de démarrage. De manière à tenir compte à la fois de la phase de connexion (login shell) et des shells interactifs (non login interactive shell), une solution est d'articuler la lecture des fichiers ~/.bash_profile et ~/.bashrc comme suit :
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# exportation de variables :
...
et :
# définition d'alias et fonctions
...
Ainsi, les variables utiles à la configuration de l'environnement sont initialisées une fois pour toutes à la connexion. Ce qui suit est un extrait des fichiers de configuration de l'auteur :
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
export PATH=~/bin:$PATH
export MANPATH=~/man:$MANPATH
export POVINI=~/povray3.6/povray.ini
export TEXINPUTS=~/LaTeX/myinputs:
export LD_LIBRARY_PATH=~/lib:~/src/lib:~/lib/GL
PS2="et?> "
HISTCONTROL=ignoreboth
umask 027
et :
alias rm='rm -i'
alias mv='mv -i'
alias cp='cp -i'
alias up='cd ..'
alias uup='cd ../..'
alias ou='find . -name '
alias ltr='ls -ltr'
function cleantex()
{
/bin/rm -f $1.aux $1.log $1.bbl $1.blg $1.mtc* $1.?dx\
$1.?lg $1.?nd $1.toc
}
Pour ajouter un répertoire personnel à la liste des répertoires de recherche, le shell bash pris comme support dans ce manuel permet d'écrire :
export PATH=~/bin:$PATH
Cependant certains shells ne procèdent pas à l'expansion du ~, il faudra alors écrire :
PATH=~/bin:$PATH export PATH
6-1-7. Étude(s) de cas▲
6-1-7-a. Un autre LATEX▲
Lorsqu'on utilise ce merveilleux et monstrueux logiciel qu'est LATEX pour produire des documents, on fait appel à deux programmes distincts :
-
on lance le visualiseur de document xdvi avec la commande :
Sélectionnezxdvi madoc.dvi &
-
puis, à intervalles réguliers, on lance la compilation du source :
Sélectionnezlatex madoc.tex
Une fois la compilation terminée, il faut rendre active la fenêtre de logiciel xdvi pour visualiser les changements dans le document. Or, en lisant la documentation de xdvi on peut tomber sur :
- SIGNALS
When xdvi receives a USR1 signal, it rereads the dvi file.
L'idée qui germe donc dans l'esprit du lecteur d'esprit vif est la suivante : il serait intéressant de pouvoir envoyer automatiquement ce signal au programme xdvi à chaque compilation avec LATEX, et ce pour éviter d'avoir à cliquer sur la fenêtre du visualiseur pour la rendre active… Voici l'algorithme proposé :
Et voici comment on peut implémenter cet algorithme en shell :
function latex
(
)
{
# on enlève l'éventuelle extension
j
=
${1%.*}
# appel du vrai LaTeX
command latex $j
# récupération du pid de(s) xdvi(s)
pids
=
$
(
ps -ef |
grep xdvi.bin |
grep $j
.dvi \
|
awk '{print $2}'
)
# envoi du signal USR1 pour chacun d'eux
for
p in
$pids
; do
kill -USR1 $p
done
}
On notera que dans la fonction, on fait appel à command latex pour éviter un appel récursif à la fonction. Le reste de la fonction fait appel à des outils (ps, grep, awk, boucle for du shell) présentés dans les chapitres précédents (en particulier les chapitres 2Chapitre 2 - Petit guide de survie et 3Chapitre 3 - La boîte à outils).
Il est intéressant de noter que la commande fuser permettant d'obtenir la liste des processus utilisant un fichier particulier, nous offre une autre solution au problème. En effet si on tape :
$ fuser guide-unix.dvi
guide-unix.dvi: 2587
$
alors le système nous indique que le processus de pid 2587 a ouvert le fichier en question. La version de fuser de votre serviteur permet en outre à l'aide de l'option -k d'envoyer un signal particulier au(x) processus détecté(s). Ainsi :
$ fuser -k -USR1 guide-unix.dvi
$
permet d'envoyer le signal USR1 aux processus utilisant guide-unix.dvi…
6-1-7-b. Une poubelle▲
Sous unix, l'utilisateur n'a généralement pas la possibilité de récupérer un fichier qu'il a effacé. La solution adoptée par les systèmes d'exploitation consiste à proposer à l'utilisateur une « corbeille » dans laquelle on déplace les fichiers plutôt que de les effacer réellement(90). Lorsque la corbeille est vidée, les fichiers sont effectivement effacés. Il est tout à fait possible d'envisager de configurer l'environnement de travail pour mettre en place un tel mécanisme.
Voici quelques ébauches que le lecteur pourra lui-même faire évoluer selon ses besoins :
CORBEILLE
=
~/.corbeille
#
# nouvelle commande rm
#
function rm
(
)
{
# si la corbeille n'existe pas, on la crée
if
[ !
-d $CORBEILLE
]; then
mkdir $CORBEILLE
fi
# on déplace tous les fichiers de la ligne de commande
# dans la corbeille
mv -f "
$
@"
$CORBEILLE
}
Cette nouvelle commande rm peut être utilisée aussi bien pour un ensemble de fichiers que pour un ensemble de répertoires. On peut également créer une commande de vidange de la corbeille :
function vidange
(
)
{
rm -rf $CORBEILLE
}
Cette nouvelle version de la commande rm est limitée par le fait que tous les fichiers et répertoires effacés sont déplacés dans le même répertoire (celui faisant office de corbeille). Par conséquent :
- il n'y aucune trace dans la corbeille du répertoire dans lequel était initialement stocké le fichier ou répertoire effacé ;
- si on efface deux fichiers portant le même nom, seul le dernier sera sauvegardé dans la poubelle ;
- si on efface un répertoire portant le nom d'un fichier déjà effacé le shell nous enverra sur les roses avec le message :
mv: cannot overwrite non-directory ‘ /.corbeille/dir' with directory ‘dir/'
Enfin, cette fonction ne traite pas le cas des options éventuellement passées en ligne de commande. Pour éviter d'écraser un fichier déjà dans la corbeille, on peut utiliser l'option backup de la commande mv du projet gnu :
mv -f --backup=numbered $* $CORBEILLE
Cette option permettra de numéroter les fichiers dupliqués en faisant appel à la syntaxe :
- nom du fichier.~numéro~
Par exemple, toutes les sauvegardes du fichier bidule.txt, seront nommées :
bidule.txt bidule.txt.~1~ bidule.txt.~2~ bidule.txt.~3~ ...
6-2. Avec vi▲
vi - prononcer vi aïe - est l'éditeur de référence des systèmes unix; c'est en quelque sorte le « dénominateur commun » des éditeurs de texte dans la mesure où la majorité des systèmes unix possède au moins cet éditeur. C'est une des raisons pour lesquelles il est bon de connaître le principe de son fonctionnement. Le concept le plus important de vi est qu'il fonctionne selon deux modes :
- Mode commande : dans ce mode on peut passer des ordres d'édition à vi (effacement d'une ligne, déplacement du curseur, etc.).
- Mode insertion : dans ce mode on peut saisir du texte.
Ce principe quelque peu archaïque(91) peut surprendre au premier abord, c'est pourquoi nous avons dressé une liste des « pourquoi » utiliser vi :
- parce que dans certaines situations, seul vi est disponible : par exemple lorsqu'on se connecte sur une machine distante pour modifier un fichier ;
- parce que c'est « puissant », en effet derrière un aspect simpliste(92) et rudimentaire(93) se cache une multitude de fonctionnalités surprenantes pour l'édition de texte ;
- parce que c'est « léger », donc le lancement est très rapide, et peu de ressources mémoire ou calcul sont grevées ;
- et enfin parce que ça fait snob ;-)(94)
Après cette introduction, voici quelques commandes de vi à connaître, ces commandes suffisent à survivre dans la majorité des cas :
i | passe en mode insertion (on peut alors « taper » du texte) ; |
ESC | revient en mode commande (quitte le mode insertion) ; |
:w | sauve le fichier ; |
:q | quitte vi. Cette commande et la précédente peuvent être utilisées en même temps (:wq) et dans le cas où l'on doit forcer la sauvegarde ou la sortie il est nécessaire d'ajouter un !, par exemple (:q!), pour quitter vi sans sauver même si le fichier a été modifié ; |
dd ou n dd | efface une ou n lignes ; |
a | passe en mode insertion après le curseur ; |
ˆ ou $ | va en début ou fin de ligne (ces deux commandes rappellent la syntaxe des expressions régulières) ; |
/ motif | cherche la chaîne motif dans le texte ; |
n | cherche l'occurrence suivante ; |
. | répète la dernière action ; |
cw texte ESC | remplace par texte la portion comprise entre le curseur et la fin du mot courant (change word) ; |
w ou b | avance ou recule d'un mot ; |
o ou O | insère une ligne vierge et commence l'insertion en dessous ou au-dessus du curseur ; |
Y ou n Y | copie une ou n lignes (yank) |
p ou P | colle le texte copié (ou coupé) par n'importe quelle commande qui copie (par exemple Y) ou qui coupe (par exemple d) en dessous ou au-dessus de curseur ; |
Voici un exemple de « rechercher/remplacer » dans vi (95) :
$ vi bidule
...
$
Puis une fois dans l'éditeur taper les commandes suivantes pour remplacer la chaîne « machin » par la chaîne « chose » :
2.
3.
4.
5.
/machin Entrée <--------------- cherche la première occurrence
cw chose Esc <------------------------------------ la remplace
n <--------------------------------------- cherche la suivante
. <------------------------------------- la remplace à nouveau
répéter à partir de 3 tant que c'est nécessaire.
Le même remplacement peut se faire en mode commande en tapant :
:%s/machin/chose/g
Sur certains systèmes, le vi disponible est vim pour vi improved (soit vi « amélioré », ce qui en dit long sur l'état du premier(96)). Cette version est moins légère que la version originale, mais apporte beaucoup de fonctionnalités et des facilités pour sa configuration.
6-3. Avec Emacs▲
(97)Présenter Emacs en quelques pages est une tâche difficile. Donner envie au lecteur d'utiliser ce logiciel extraordinaire en est une autre. La première chose que l'on peut dire au sujet de cet « éditeur de texte à tout faire » est que son nom est une contraction de Editing MACroS et que son origine remonte à 1976, date à laquelle Richard M. Stallman, fondateur du projet GNU, commença le développement d'Emacs.
Emacs fait partie des « stars » des logiciels libres, dans le sens où c'est sans doute un modèle de logiciel ouvert. À l'instar de LATEX, les utilisateurs enthousiastes ont montré que grâce à cette ouverture on pouvait ajouter de nombreuses fonctionnalités à ce logiciel fascinant. Emacs est essentiellement utilisé pour les facilités qu'il apporte à l'édition de fichier source au sens large du terme ; l'auteur - qui en a une expérience somme toute assez maigre - a pu éditer les fichiers suivants : scripts shell, langage C, C++, Lisp, Pascal, Perl, PostScript, script MATLAB, fichiers LATEX et HTML, des Makefiles, script de Persistence of Vision, et tout ceci en bénéficiant de l'insertion de commentaires, de l'indentation automatique et de la mise en évidence des mots-clés en couleur, entre autres choses. Mais bien que son rôle premier soit l'édition de fichiers texte, il est aussi capable de jouer aux tours de hanoï (M-x hanoi), au morpion (M-x gomoku), à Tétris (M-x tetris), de vous psychanalyser (M-x doctor), de lire les mails et les news, de transférer des fichiers par ftp, de compulser un calendrier (M-x calendar) permettant notamment de savoir que la date du jour (4 juillet 2000) correspondant au septidi de Messidor de l'année 209 de la Révolution française, éditer des fichiers en hexadécimal (M-x hexl-mode), j'en passe et des pires…
Cette section est une introduction aux concepts fondamentaux d'Emacs ainsi qu'aux commandes à connaître pour y prendre goût. Nous donnons en fin de ce paragraphe quelques idées pour chercher de l'aide pour les explorations futures.
6-3-1. Concepts de base▲
Pour commencer, il est important de noter qu'Emacs a la particularité de pouvoir s'exécuter aussi bien en mode texte dans un terminal qu'en mode graphique (ou fenêtre) en s'appuyant sur un serveur X. Dans l'un ou l'autre des modes, on pourra utiliser les commandes présentées dans cette section.
Les objets graphiques qui composent l'éditeur Emacs sont les suivants :
Frame : Emacs est multifenêtre, et nomme chacune d'elles frame(98). La figure 6.1 montre une session avec deux frames ;
Window : les frames contiennent une ou plusieurs windows. La figure 6.1 montre trois windows : une dans la frame de gauche et deux dans la frame de droite ;
Buffer : les données qui sont affichées dans les windows sont des zones mémoires appelées buffers. Ces zones contiennent du texte à éditer. Un buffer peut être sauvegardé sur disque, créé à partir d'un fichier, etc. En fait sous Emacs, « tout est buffer » ;
Minibuffer : buffer particulier composé d'une ligne tout en bas de chaque frame.
C'est dans cette zone qu'a lieu la majeure partie des interactions avec l'utilisateur ;
Status bar : ou barre d'état, située en bas de chaque window, elle indique différentes informations ; ici : le nom du fichier, l'heure, la position du curseur, le mode d'édition (cf. plus bas), etc. :
Menu : chaque frame dispose d'un menu permettant de lancer diverses fonctions.
Les deux autres concepts fondamentaux sont les suivants :
Commandes : toute action exécutée dans l'éditeur, quelle qu'elle soit, est le résultat de l'interprétation d'une fonction Lisp(99). Cette fonction peut être appelée par son nom, par une combinaison de touches, ou par le biais du menu. Il faut noter que toutes les fonctions n'ont pas nécessairement de combinaison de touches ou d'entrée dans le menu ;
Mode : chaque buffer est « piloté » par Emacs dans un mode particulier. Le mode en question correspond à la manière dont les commandes vont être interprétées. À titre d'exemple, les fonctions d'indentation, de mise en couleur, de mise en commentaire, sont interprétées différemment selon qu'Emacs est en mode LATEX, ou en mode C pour ne citer que ceux-là.
6-3-2. Notations utilisées▲
Dans les diverses documentations que l'on trouve traitant d'Emacs, et dans emacs lui-même, on retrouve les notations suivantes au sujet des combinaisons de touches :
-
C-t : pour une pression sur et la touche t ;
-
M-t : désigne l'utilisation de la touche « Meta » :
-
une pression sur et la touche t, ou à défaut :
-
une pression sur puis la touche t.
-
-
ESC : la touche ;
-
RET : la touche ;
- SPC : la barre d'espacement ;
Ainsi :
-
M-x signifie et ou puis ;
-
C-x C-c signifie et et et , que l'on peut obtenir en maintenant enfoncée tout en tapant dans l'ordre puis .
6-3-3. Appeler une commande▲
À partir de l'exemple de la commande d'ouverture d'un fichier, nous allons passer en revue quelques-unes des notions importantes d'Emacs concernant l'appel des commandes.
On peut appeler la commande d'ouverture de fichier (find-file) de quatre manières :
- par son nom à l'aide de la combinaison : M-x find-file ;
- à l'aide de la combinaison : C-x C-f ;
- à l'aide d'un éventuel raccourci clavier défini sur votre installation ;
- à l'aide de l'entrée File/Open File dans la barre de menu.
6-3-3-a. Le minibuffer▲
Dans les trois cas le lancement de cette commande donne le focus au minibuffer, et l'utilisateur doit entrer le nom du fichier qu'il veut ouvrir ou un nom quelconque pour créer un nouveau buffer.
-
M-x find-file monfichier.txt
Dans le minibuffer la touche « Espace » () ou « Tab » () permet de compléter automatiquement un nom de commande ou un nom de fichier. En cas d'équivoque une pression sur ces touches crée une nouvelle window avec un buffer contenant les différentes alternatives possibles à la complétion. Par exemple si on tape :
-
M-x find
on fait apparaître une fenêtre contenant le buffer suivant :
Click mouse-2 on a completion to select it.
In this buffer, type RET to select the completion near point.
Possible completions are:
find-alternate-file find-alternate-file-other-window
find-dired find-file
find-file-at-point find-file-literally
find-file-other-frame find-file-other-window
find-file-read-only find-file-read-only-other-frame
find-file-read-only-other-window find-function
find-function-at-point find-function-on-key
find-function-other-frame find-function-other-window
find-grep-dired find-name-dired
find-tag find-tag-noselect
find-tag-other-frame find-tag-other-window
find-tag-regexp find-variable
find-variable-at-point find-variable-other-frame
find-variable-other-window
qui montre donc toutes les commandes dont le nom commence par « find ». Donc en tapant les deux premiers caractères :
-
M-x find fi
on complète jusqu'à find-file et il est alors possible de saisir le nom du fichier que l'on veut charger. On notera que la complétion automatique fonctionne aussi sur les noms de fichiers. Enfin, la fenêtre d'information vous indique également que vous pouvez utiliser le bouton du milieu de votre souris(100) pour choisir le fichier parmi la sélection.
6-3-3-b. Stop !▲
Pour interrompre une action entreprise dans le minibuffer, il faut utiliser la combinaison C-g qui appelle la fonction keyboard-quit. Cette fonction est également utile pour interrompre l'exécution d'une commande.
Lorsqu'on débute sous Emacs, on a tendance à « laisser traîner » son curseur dans le minibuffer ; ce qui peut entraîner un comportement étrange de l'éditeur qui vous narguera par des :
- Command attempted to use minibuffer while in minibuffer
dans ce cas une ou deux pressions sur C-g remet Emacs dans le droit chemin.
6-3-3-c. Historique▲
La combinaison C-x ESC ESC rappelle la dernière commande exécutée. Les touches et dans le minibuffer permettent alors de choisir et éventuellement modifier l'une des dernières commandes exécutées :
Redo: (find-file "˜/tcqvatvs/guide/chap-configurer.tex" 1)
cet historique permet en outre d'avoir une première idée de la syntaxe d'appel des commandes Lisp.
6-3-3-d. Arguments et répétition▲
Certaines commandes d'Emacs attendent un argument numérique. On peut passer cet argument en préfixant l'appel de la commande par C-u n, pour passer la valeur n.
Si la commande en question n'attend pas d'argument elle sera simplement exécutée n fois. Par exemple la séquence : C-u 24 a, insère :
- aaaaaaaaaaaaaaaaaaaaaaaa
dans le buffer courant.
6-3-4. Manipuler les objets d'Emacs▲
Les objets d'Emacs - frame, window, buffer, etc. - peuvent être manipulés via un certain nombre de fonctions qu'il est souhaitable de connaître.
Frame - les tâches courantes autour des frames sont la création et la destruction. On crée une nouvelle frame avec :
- C-x 5 2 ou :
- M-x make-frame-command
- par le menu File/Make New Frame
on détruit celle sur laquelle on se trouve avec :
- C-x 5 0 ou :
- M-x delete-frame
- en cliquant sauvagement sur le bouton « delete window » de son gestionnaire de fenêtres préféré.
Il est bien évident que les frames d'Emacs ne sont disponibles que dans un environnement permettant le « multifenêtrage » comme X window…
Window - on peut créer de nouvelles fenêtres dans une frame à partir de la première :
- C-x 3 « divise horizontalement » la window actuelle ;
- C-x 2 « divise verticalement » la window actuelle ;
- C-x 1 ne conserve que la window contenant le curseur
ces combinaisons de touches correspondent respectivement aux fonctions :
- M-x split-window-horizontaly ;
- M-x split-window-verticaly ;
- M-x delete-other-windows.
Il est particulièrement intéressant de noter qu'après une série de C-x 2 et C-x 3 - dans cet ordre - on obtient un quad tree à la mode Emacs (voir figure 6.2).
Mais ne nous égarons pas dans des considérations douteuses, puisqu'on peut aussi redimensionner une fenêtre coupée en deux horizontalement (après un C-x 2) à l'aide de :
- C-x ˆ ou M-x enlarge-window ;
- en déplaçant la status bar à l'aide du bouton du milieu de votre souris.
buffer - on peut « tuer » un buffer, lorsqu'on a fini d'éditer un fichier, ou simplement parce que le buffer en question n'est plus utile lors de la session, avec :
- C-x C-k ou
- M-x kill-buffer, ou :
- le menu File/Kill Current Buffer
Notez bien que si le buffer a été modifié depuis la dernière sauvegardeManipulation de fichiers, vous devrez répondre à quelques questions qui vous seront gentiment posées par le truchement du
minibuffer. Il est également possible d'avoir la liste de tous les buffers ouverts depuis le début de la session avec :
- C-x C-b ou M-x list-buffers, ou :
- par le menu Buffers/List All Buffers
Une partie de cette liste est visible dans les premières entrées du menu Buffers.
6-3-5. Les tâches basiques▲
6-3-5-a. Se déplacer / effacer▲
Malgré ce que dit le tutoriel d'Emacs, qui préconise l'usage des combinaisons (C-f, C-b, C-n et C-b) pour déplacer le curseur, il semble raisonnable de penser qu'en ce début de siècle, on peut utiliser les flèches du clavier. Il est cependant intéressant de noter que ces raccourcis existent - ils sont facilement mémorisables : forward, backward, next, previous - pour les utiliser en cas d'urgence. Les autres combinaisons utiles pour se déplacer sont :
- C-e/C-a va en fin/début de ligne ;
-
C- et C- va un mot vers la gauche et vers la droite respectivement (on pourra également utiliser M-f (forward) et M-b (backward) ;
-
C- et C- va un paragraphe vers le haut et vers le bas respectivement ;
- C-l centre verticalement le curseur au milieu de la window courante en déplaçant le texte le cas échéant ;
-
M-< et M-> permettent d'aller ou début et à la fin du buffer, ces fonctions sont également disponibles avec les touches et si votre clavier en dispose ;
Pour effacer du texte, les touches « delete » et « backspace » ont l'effet escompté. On peut en outre effacer à partir du curseur jusqu'à la fin de la ligne avec C-k. Cette opération s'apparente à un « couper » puisque le texte effacé est stocké pour éventuellement être collé. Notez également que M- efface le mot avant le curseur.
6-3-5-b. Sélectionner▲
Pour sélectionner une zone, il suffit de se placer au début de la zone que l'on veut traiter et appuyer sur C-SPC. En fonction de la configuration d'Emacs, lorsqu'on déplace le curseur, on voit apparaître la zone sélectionnée en « inverse vidéo ». La souris permet également de sélectionner une zone, bien entendu.
6-3-5-c. Copier, Couper, Coller…▲
Une fois la zone sélectionnée, on peut procéder aux trois opérations classiques :
- C-w : couper ;
- C-y : coller ;
- M-w : copier.
Le « coller » d'Emacs apporte beaucoup de souplesse, puisqu'une fois la séquence C-y entrée, on peut éventuellement choisir le texte à coller grâce à la combinaison M-y qui permet de choisir une sélection parmi les zones copiées ou coupées jusqu'à présent.
6-3-5-d. Défaire, refaire▲
Emacs dispose d'un « undo » permettant de « remonter » jusqu'aux premières modifications apportées lors du démarrage de la session. Le « undo » s'obtient grâce à la combinaison C-_ ou C-x u(101).
Une propriété intéressante du « undo » d'Emacs est qu'il peut aisément se transformer en « redo ». Pour cela il suffit de taper le fameux C-g. Si on peut voir le « undo » comme une « remontée vers le passé », un C-g permet de faire en sorte que l'utilisation du C-_ suivant « revienne vers le futur » :
abcdef | ||
C-_ | abcde | undo |
C-_ | abcd | undo |
C-g | bcd | glurps ! |
C-_ | abcde | redo |
6-3-5-e. Manipulation de fichiers▲
Les trois opérations qui sont indubitablement utiles sont :
La sauvegarde : qui sauve le contenu du buffer dans un fichier est obtenue grâce à :
- C-x C-s ou M-x save-buffer, ou :
- menu File/Save Buffer.
Le chargement : permet d'insérer le contenu d'un fichier dans un buffer tout neuf. Si le fichier n'existe pas, un buffer est créé portant le nom spécifié et la sauvegarde suivante créera le fichier sur le disque. Nous avons vu précédemment que le chargement pouvait être réalisé grâce à :
- la commande M-x find-file, ou
- le raccourci C-x C-f, ou
- le menu File/Open File.
La mise à jour : il arrive que le fichier dont on a un buffer dans Emacs soit modifié par une source extérieure (un autre programme). Dans ce cas la « copie » dont on dispose dans le buffer n'est plus à jour par rapport au contenu du fichier, il faut donc utiliser la commande :
- M-x revert-buffer ou :
- menu File/Revert Buffer
qui recharge le contenu du fichier dans le buffer courant. Dans cette situation, Emacs avertit l'utilisateur par plusieurs messages dans le minibuffer.
D'autres opérations peuvent être utiles à connaître comme le célèbre « sauver sous » (C-x C-w ou M-x write-file) qui sauve le buffer dans un fichier portant un autre nom. Est également intéressante M-x insert-file (ou C-x i) qui insère à l'endroit où est le curseur le contenu d'un fichier.
6-3-5-f. Rechercher/Remplacer▲
Voici les deux fonctions à connaître pour rechercher des chaînes de caractères dans un buffer et éventuellement les remplacer.
Juste chercher… La première est la fonction M-x isearch-forward dont un raccourci pratique est C-s. Dès que la combinaison C-s est pressée, Emacs attend par l'intermédiaire du minibuffer les lettres composant la chaîne de caractères à rechercher. À chaque lettre entrée, le curseur se déplace sur la première partie du texte correspondant à la chaîne formée jusque là. On a alors plusieurs alternatives :
- la chaîne est introuvable (message Failing I-search) ;
- la chaîne a été trouvée : en pressant à nouveau sur C-s le curseur se positionne sur l'occurrence suivante ;
- si on presse C-g le curseur se repositionne là où il se trouvait au début de la recherche et celle-ci s'arrête ;
-
si on presse , le curseur reste dans sa position actuelle et la recherche s'arrête.
Le pendant de C-s est C-r qui effectue le même travail, mais en cherchant « vers le haut » (M-x isearch-backward). On peut d'ailleurs passer du « backward » au « forward » sans problème lors d'une recherche.
Chercher et remplacer - La fonction M-x query-replace, dont le raccourci est M-%, permet, comme son nom l'indique, de chercher une chaîne et de la remplacer par une autre. Le minibuffer vous demandera donc deux chaînes pour effectuer les remplacements. Si une chaîne est trouvée, Emacs vous demandera ce que vous désirez faire, vous pourrez alors répondre :
- y pour remplacer ;
- b pour ne pas remplacer ;
- ! pour remplacer partout ;
- q pour quitter ;
- h pour voir les autres possibilités !
Une particularité de cette commande est qu'elle peut agir uniquement sur une zone si elle est préalablement sélectionnée. Notez aussi qu'Emacs est généralement configuré pour préserver les majuscules dans le remplacement, c'est-à-dire que dans un texte où l'on demande de remplacer « a » par « b », « A » sera remplacé par « B ».
Il existe une version améliorée de la commande M-x search-replace : la commande query-replace-regexp (dont le raccourci est M-C-%) qui permet de chercher et remplacer des chaînes spécifiées à partir d'expressions régulièresgrep et la notion d'expressions régulières. Par exemple :
-
M-C-% ^b.*e$ hoplà
dans le texte de gauche, donne le texte de droite :
bcde | hoplà |
bbd | bbd |
cde | cde |
bqmlksdjfe | hoplà |
Nous rappelons que ^b.*e$ signifie : une ligne qui commence par « b » suivi d'une série de caractères et finissant par « e ».
6-3-5-g. Indenter/Commenter▲
Un des plaisirs que l'on peut tirer de l'utilisation de ce gros patapouf d'Emacs(102) est l'indentation automatique des sources et l'insertion de commentaires(103). Il n'y a rien de difficile à apprendre dans ce paragraphe puisque tout est fait automatiquement en fonction du mode utilisé. Prenons l'exemple d'un fichier C++. À chaque pression sur la touche le curseur se mettra à la « bonne place », c'est-à-dire en fonction de l'imbrication des diverses boucles et autres blocs. Si le curseur ne se met pas à une position correcte, c'est que le source comporte une erreur de syntaxe. Il y a trois commandes à connaître :
- M-x indent-region qui indente la zone sélectionnée en fonction du mode utilisé ;
- M-x comment-region qui commente la région sélectionnée en fonction de la syntaxe du langage correspondant au mode d'Emacs pour le buffer ;
- C-u M-x comment-region qui retire les commentaires de la zone sélectionnée.
Lorsqu'Emacs est en mode langage C, on peut commenter une région préalablement sélectionnée avec le raccourci C-c C-c. Pour décommenter on pourra utiliser le raccourci C-u C-c C-c.
6-3-6. Emacs et les Makefiles▲
La commande M-x compile permet d'exécuter une commande dans un shell fils d'Emacs. Ainsi lorsqu'on lance cette fonction, le minibuffer attend une commande à exécuter :
Compile command: make
On peut alors remplacer make par la commande de son choix, par exemple echo salut les coins coins et presser la touche . La commande est alors exécutée dans un shell et le résultat est affiché dans un buffer nommé *compilation* :
cd /home/vincent/LaTeX/tcqvatvs/guide/
echo salut les coinscoins
salut les coinscoins
Compilation finished at Wed Jul 5 23:17:32
Ce qui n'est certes pas passionnant. Cependant si en lieu et place d'un bonjour aux canards, on invoque make, cela devient plus intéressant. En effet, en éditant un fichier C (par exemple), on peut lancer la compilation dans Emacs. L'éditeur devient alors un environnement de développement qui se suffit à lui-même. Le buffer *compilation* peut en effet être utilisé pour cerner les erreurs de compilation. La figure 6.4b montre le contenu de ce buffer lorsque le source contient une erreur. Un clic de souris avec le bouton du milieu sur la ligne contenant l'erreur positionne le curseur à la ligne du programme source correspondant.
6-3-7. Personnaliser▲
6-3-7-a. Macros▲
Si on reprend l'étymologie du mot Emacs on pense à « macro ». Les macros sont des séquences de touches que l'utilisateur peut enregistrer et réutiliser plus tard. Le principe d'enregistrement d'une macro est le suivant :
- commencer l'enregistrement ;
- tapoter sur le clavier la séquence de touches qu'on veut mémoriser ;
- finir l'enregistrement ;
- donner un nom à la macro définie ;
- stocker éventuellement le « code » de la macro.
Le commencement et la fin de l'enregistrement sont stipulés par les commandes M-x start-kbd-macro et M-x end-kbd-macro dont les raccourcis élégants sont « C-x ( » et « C-x ) ». Toute touche tapée entre le début et la fin de l'enregistrement est stockée dans la macro courante. On peut ensuite donner un nom à la macro définie avec M-x name-last-kbd-macro, et enfin insérer le code Lisp de cette macro dans le fichier de démarrage à l'aide de la commande M-x insert-named-kbd-macro. Voyons un exemple : c'est une pratique courante en langage C, d'insérer dans les fichiers include la directive de compilation suivante :
#ifndef __BIDULE_H
#define __BIDULE_H
(
...contenu du fichier include...)
#endif
Pour éviter d'insérer systématiquement ces directives, à chaque création d'un fichier include, on peut envisager de créer une macro de la manière suivante :
- top départ : C-x ( <-------- à partir d'ici tout ce qu'on tape est enregistré
-
enregistrement de la macro :
- M-x < <--------------------------------- aller au début du buffer
-
#ifndef ___H
-
#define ___H
- M-x > <---------------------------------- aller à la fin du buffer
-
#endif
- C-x ) : fin d'enregistrement.
- donner un nom à la macro avec M-x name-last-kbd-macro : dans le minibuffer on répond par exemple insert-ifndef qui est ma foi un nom très seyant pour cette macro.
On peut maintenant utiliser cette macro comme une autre commande. Il manque à notre exemple l'association d'une combinaison de touche à cette macro et la sauvegarde de cette macro pour les sessions suivantes ; c'est l'objet des paragraphes suivants.
6-3-7-b. Raccourcis clavier▲
On peut associer une combinaison de touches à une fonction en utilisant la commande M-x global-set-key. Cette commande demande à l'utilisateur la combinaison puis la fonction à y associer. On pourra par exemple associer la combinaison de touches F5 (ou F10, ou C-x C-…)(104) à la fonction qui commente une région :
6-3-7-c. Le fichier .emacs▲
On peut stocker des configurations personnelles - telles que des raccourcis clavier par exemple - dans un fichier qui est chargé à chaque lancement d'Emacs. Ce fichier doit porter le nom .emacs et doit résider dans le répertoire privé de l'utilisateur. La « petite » difficulté réside dans le fait que le contenu de ce fichier doit être en Lisp. La composition d'un fichier .emacs dépasse le cadre de ce manuel(105) c'est pourquoi nous donnerons ici quelques possibilités :
; pour preserver les liens lors d'une sauvegarde :
(setq backup-by-copying-when-linked t)
; remplace une selection par ce que l'on tape
(delete-selection-mode t)
; numero de colonne
(setq column-number-mode t)
; bip visible et non sonore
(setq visible-bell t)
Notez tout de même, qu'un moyen possible pour construire son propre fichier .emacs peut consister à :
- exécuter la commande que l'on veut sauvegarder dans le .emacs, par exemple M-x standard-display-european pour afficher les caractères accentués ;
- faire apparaître le code Lisp d'appel dans le minibuffer avec l'historique C-x ESC ESC ;
- copier ce code dans son .emacs : (standard-display-european nil) en utilisant le mécanisme de copier/coller d'Emacs ;
- recharger le .emacs avec la commande M-x load-file
Cette méthode est bien entendu limitée à l'ajout de fonctionnalités simples.
6-3-7-d. Francisation▲
Pour forcer Emacs à afficher les caractères accentués, il peut être nécessaire de lancer la commande M-x standard-display-european. Ainsi la phrase qui par défaut s'affichait comme ceci :
cet apr\350s midi d'\351t\351 \340 la campagne...
s'affichera comme cela :
cet après midi d'été à la campagne...
6-3-7-e. Modes▲
Comme on l'a entr'aperçu un peu plus haut, chaque buffer est piloté par un mode particulier qui gère l'indentation, la mise en couleur, etc. Ce mode est indiqué dans la barre d'état.
À chaque chargement de fichier, Emacs se place dans un mode d'édition particulier en fonction de l'extension du fichier. Cette reconnaissance peut échouer dans certains cas. On peut alors basculer manuellement dans le mode désiré avec les commandes M-x c++-mode, sh-mode, latex-mode, etc.
On peut également charger le mode désiré de manière automatique. Un exemple : lors du chargement d'un fichier dont l'extension est .h, le mode C est lancé ; si l'on préfère le mode C++, il faudra insérer dans son .emacs :
(setq auto-mode-alist
(cons '("\\.h\\'" . c++-mode) auto-mode-alist))
Certains modes sont dits mineurs par opposition aux modes majeurs (minor and major modes) dans la mesure où ils sont chargés en plus du mode majeur. C'est le cas par exemple des modes :
- M-x outline-minor-mode qui permet d'utiliser un mode « plan » dans les fichiers LATEX offrant la possibilité de masquer certaines sections (paragraphes, sous paragraphes, etc.) ;
- M-x auto-fill-mode qui permet de passer à la ligne automatiquement dans les buffers en fonction d'un nombre de caractères défini pour chaque ligne.
On peut charger ces modes mineurs grâces aux commandes introduites ci-dessus, ou automatiquement en utilisant la notion de hook. Un hook associé à un mode donné est, entre autres, un moyen d'exécuter des commandes lorsque le mode en question est chargé. Les deux lignes suivantes dans votre .emacs :
(add-hook 'LaTeX-mode-hook
(function ( lambda() (auto-fill-mode))))
(add-hook 'LaTeX-mode-hook
(function ( lambda() (outline-minor-mode))))
chargent automatiquement les modes outline et auto-fill lorsqu'un fichier LATEX est chargé avec le LaTeX-mode.
6-3-7-f. Le « bureau »▲
Lors d'une session Emacs, on ouvre une quantité de buffers plus ou moins importante. Il est agréable de pouvoir recharger ces buffers lors de la session suivante. Pour ce faire il faut procéder en deux temps :
-
ajouter la ligne :
- (desktop-read) ; chargement du bureau
dans son .emacs (le caractère « ; » est le commentaire du Lisp) ;
- exécuter la commande M-x desktop-save (une seule fois suffit). Précisez que vous voulez sauver votre bureau dans votre répertoire racine, et le tour est joué.
À chaque lancement d'Emacs, vos buffers seront chargés. Si vous êtes curieux vous pouvez jeter un œil dans le fichier .emacs.desktop qui contient une description des fichiers à charger. Notez que la sauvegarde du bureau ne tient pas compte des frames.
6-3-8. À l'aide▲
La touche magique pour obtenir de l'aide à partir d'emacs est C-h. Cette touche est un préfixe aisément mémorisable qui, associé avec d'autres combinaisons fournit les informations suivantes :
- C-h C-k donne la signification de la combinaison de touches que vous taperez (k pour key) ; c'est aussi utile pour savoir si une combinaison de touche est active ;
- C-h C-f décrit la fonction dont vous donnerez le nom ;
- C-h C-t lance le très instructif tutoriel d'Emacs ;
- C-h C-i lance l'ensemble des manuels au format infoLe format info installés sur votre ordinateur ; il y a bien sûr le manuel d'Emacs.
6-4. Avec Xwindow▲
Mais qu'est-ce donc que cet étrange X, ou X window ou Xlib ? Derrière ce joli nom se cachent plusieurs concepts réunis en un seul : une interface graphique, un protocole réseau et une bibliothèque de développement ! On peut voir X comme la couche intermédiaire entre le matériel et les applications graphiques. Pour l'instant on peut se contenter de dire que la couche X est la couche nécessaire pour pouvoir utiliser unix en mode graphique, c'est-à-dire dans un environnement multifenêtre, avec des jolis menus, la souris et tout.
6-4-1. Principe général▲
X est basé sur le principe de client-serveur. Les rôles de l'un et l'autre des acteurs sont les suivants :
Serveur : c'est le logiciel qui a pour but de piloter la carte graphique et l'écran de la machine destinée à afficher, ainsi que répondre au mouvement de la souris et aux pressions des touches du clavier. Il faut qu'il y ait un serveur X en attente sur une machine pour pouvoir accéder à la couche graphique.
Le client : c'est l'application qui après s'être connectée au serveur, l'utilise pour effectuer entre autres les affichages. Par exemple, si vous utilisez un navigateur pdf ou un visualiseur ps pour consulter ce document, les affichages sont gérés par le serveur X, les événements de la souris et du clavier sont interceptés par le serveur et gérés par le client par le truchement d'une file d'attente d'événements.
En s'appuyant sur la figure 6.5 voyons quel est le principe du mode client-serveur de X :
- au lancement, le client (c'est-à-dire l'application) va se connecter au serveur ; le résultat de la connexion consiste en l'établissement d'un canal de communication entre l'application et les périphériques d'affichage et de saisie de la machine pilotée par le serveur ; ce canal en jargon X est appelé un display ;
- une fois connecté, le client va demander au serveur d'afficher un certain nombre de choses, qui correspondent à l'application elle-même ;
- le client se met alors en attente d'événements ;
- lorsque l'utilisateur presse une touche de clavier ou manipule la souris, le serveur avertit le client de la position de la souris, du bouton qui a été pressé, etc. Le client réagit alors en fonction de ces informations et envoie un ordre au serveur (par exemple si la zone où survient un clic de souris est un bouton, le client va demander au serveur d'afficher un bouton enfoncé).
6-4-2. Les différentes couches▲
Lorsqu'on est face à un environnement graphique sous unix, il faut distinguer plusieurs couches différentes :
X : c'est la couche de base, c'est in fine toujours X qui dessine à l'écran ; comme on peut le constater à la figure 6.6a, une application est exécutée dans une fenêtre qui n'est qu'un rectangle à l'écran ;
Le gestionnaire de fenêtres : c'est le programme qui « habille » les fenêtres avec des barres de titres, ascenseurs et autres fonctionnalités qui permettent à l'utilisateur de les redimensionner, déplacer, iconifier, etc. Chacun de ces programmes (appelés en anglais window managers) apporte un « look and feel » particulier à l'environnement : l'affichage (le look) et la manière de manipuler les fenêtres (le feel) dépendent du gestionnaire de fenêtres. Les plus connus sont fvwm (figure 6.6b), windowmaker (figure 6.6d), afterstep (figure 6.6c), mwm ;
Les widgets : ce sont les différents objets qui composent une application (boutons, ascenseurs, menus, boîtes de dialogue, etc.). Ces objets sont construits par le biais de bibliothèques dont les plus connues sont Xt, Xaw, Gtk, Qt, Motif, lesquelles sont bâties à partir des bibliothèques X de base ;
Les environnements intégrés : il y a quelques années, devant la multitude de choix possibles quant aux gestionnaires de fenêtres et la relative difficulté qu'il y a à configurer l'environnement graphique, plusieurs vendeurs d'unix (Sun, HP, IBM) ont décidé de créer le Common Desktop Environnement (dit CDE) destiné à homogénéiser l'interface graphique des systèmes unix. Dans le monde des logiciels libres, l'idée a également séduit et deux environnements intégrés sont nés : Gnome et Kde. Ces environnements ne seront pas traités dans ce manuel, ceci dans un souci d'ouverture. Nous préférons en effet présenter les couches inférieures pour une meilleure compréhension globale(106).
6-4-3. Comprendre le démarrage▲
Un système unix peut passer en mode graphique par deux moyens :
- directement au démarrage, dans ce cas la fenêtre de login est une fenêtre graphique et le fichier ˜/.xsession de l'utilisateur est exécuté ;
- manuellement : l'utilisateur se connecte sur une console texte, et exécute un utilitaire généralement appelé startx ou quelque chose d'approchant, qui permet de lancer l'environnement graphique ; dans ce cas précis c'est le fichier ˜/.xinitrc de l'utilisateur qui est exécuté.
Il est souvent suffisant de faire en sorte que le fichier ˜/.xsession soit un lien symbolique sur le fichier ˜/.xinitrc. Attention, ce dernier doit être exécutable. Voici un exemple de fichier de démarrage :
#!/bin/sh
# .xinitrc
# pas de beep
xset b off
# fond
xsetroot -solid lightseagreen
# un terminal pour commencer
xterm +ls &
# gestionnaire de fenêtres
exec fvwm2
On comprend qu'au lancement de X, on va successivement, imposer un bip silencieux, donner une couleur à la fenêtre racine(107), lancer un terminal X, et finalement lancer le gestionnaire de fenêtre.
Dans un tel fichier, le dernier programme - ici fvwm2 - ne doit pas être lancé en tâche de fond, et la terminaison de celui-ci implique la fin de la session X.
Le démarrage de X sur votre système n'est peut être pas tout à fait identique à ce qui est décrit plus haut. Pour savoir comment ça se passe chez vous, jouez les Hercule Poirot, et vous pourrez tomber, comme sur le système de l'auteur, sur un fichier /etc/X11/xdm/Xsession dont voici la fin :
if
[ -x "
$HOME
/.xsession"
]; then
exec "
$HOME
/.xsession"
elif
[ -x "
$HOME
/.Xclients"
]; then
exec "
$HOME
/.Xclients"
elif
[ -x /etc/X11/xinit/Xclients ]; then
exec /etc/X11/xinit/Xclients
else
exec xsm
fi
extrait que vous êtes à même de comprendre si vous avez lu attentivement le chapitre 5Chapitre 5 - Développer ! !
Nous donnons ici à nouveau et à titre d'information, l'arborescence des processusLien de parenté correspondant à une session X :
PID PPID CMD
324 1 [xdm]
334 324 \_ /etc/X11/X
335 324 \_ [xdm]
346 335 \_ [.xsession]
360 346 \_ fvwm2 -s
448 360 \_xterm -ls
451 448 | \_-bash
636 451 | \_ ps --forest -eo pid,ppid,cmd
576 360 \_ /usr/X11R6/lib/X11/fvwm2/FvwmAuto
577 360 \_ /usr/X11R6/lib/X11/fvwm2/FvwmPager
6-4-4. X et le réseau▲
Un des aspects particulièrement souples de X est sa capacité à faire communiquer le client et le serveur à travers un réseau. En d'autres termes, il est possible pour une machine distante exécutant une application graphique (client X), d'envoyer les affichages sur la machine que vous avez devant les yeux - c'est-à-dire utiliser le serveur X local. Cette idée est illustrée à la figure 6.7.
6-4-4-a. La variable d'environnement DISPLAY▲
Lorsqu'une application X démarre, elle cherche à se connecter au serveur spécifié par la variable DISPLAY - sauf si l'application a été programmée pour se connecter à un serveur spécifique. La variable DISPLAY a la forme suivante :
- machine:numéro_display.numéro_écran
machine est le nom de la machine. Selon le contexte, cela peut être :
- le nom de la machine seul : mekanik ;
- le nom complet de la machine : mekanik.zeuhl.org ;
- rien du tout, l'application cherchera à se connecter au serveur X de la machine sur laquelle elle s'exécute.
Le nombre numéro_display correspond au numéro du canal initialisé par le serveur, le premier porte le numéro 0. Dans la plupart des cas les machines n'ont qu'un seul display, c'est-à-dire qu'il n'y a qu'un seul ensemble clavier/souris qui communique avec le serveur. Ce nombre ne doit pas être omis. numéro_écran, quant à lui, est le numéro associé aux écrans attachés à un canal donné. Ainsi si une machine possède deux écrans, le premier portera le numéro 0, le suivant 1, etc. La plupart des applications dispose d'une option -display, -d ou --display pour passer outre l'effet de la variable DISPLAY, en écrivant par exemple :
$ xclock -display machine.domain.org:0 &
[1] 3452
$
qui lance une magnifique horloge sur la machine machine.domain.org si elle l'a autorisé.
6-4-4-b. Autoriser des machines à se connecter à un serveur ▲
De manière à éviter que toutes les machines connectées au même réseau que vous (par exemple Internet !) ne puissent utiliser votre serveur X, il est nécessaire d'adopter une politique d'autorisation. La première politique consiste à n'autoriser que certaines machines dont on stockera les noms dans une liste. On verra que la gestion de cette liste est effectuée par l'utilitaire xhost.
En supposant qu'un utilisateur assis devant la machine mekanik veuille utiliser les ressources de calcul de la machine distante ayler, tout en affichant sur l'écran de mekanik, voici les étapes à effectuer :
- autoriser la machine distante ayler à utiliser le serveur X de la machine locale mekanik ;
- se connecter sur ayler ;
- spécifier que le serveur X à utiliser est sur la machine mekanik ; c'est-à-dire qu'on veut afficher sur l'écran de la machine locale et non sur celui de la machine distante ayler ;
- lancer l'application !
ce qui se traduit dans un shell par(108) :
$ xhost +ayler.freejazz.org <----------------------------- autorisation
ayler.freejazz.org has been added to control list
$ rlogin ayler.freejazz.org <-------- connexion sur la machine distante
$ export DISPLAY=mekanik.zeuhl.org:0.0 <--------- affichage sur mekanik
xappli &
[1] 15678
$
6-4-4-c. Autoriser des utilisateurs à se connecter à un serveur▲
Lorsque la politique basée sur les machines est trop laxiste (autoriser une machine c'est autoriser tous les utilisateurs de cette machine), il faut envisager d'autoriser uniquement certains utilisateurs. Pour ce faire, on s'appuie sur l'utilitaire xauth qui gère un ensemble de clefs - appelées cookies dans le jargon de xauth - associées à chaque display pour un utilisateur donné. Le principe est le suivant : pour autoriser une machine B à afficher sur une machine A, il faut :
- récupérer un cookie de la machine A ;
- le faire connaître à la machine B.
Pour récupérer un cookie sur la machine locale A, on fait :
$ xauth nlist A:0
0000 0004 a1031e2f 0001 30 0012 4d49542d4d414749432d434f4f4b4
9452d310010 002e46651c4158584654595d61125506
$
qui affiche le cookie correspondant au display A:0 sur la sortie standard. Dans une autre fenêtre, on se connecte sur la machine distante, et on lance la commande :
$ xauth nmerge -
qui attend un cookie sur son entrée standard. Par un habile « copier/coller » on peut fournir le cookie de la machine A. Une solution élégante, si les deux machines le permettent, est de lancer sur la machine locale A :
$ xauth nlist A:0 | rsh B /usr/X11R6/bin/xauth nmerge -
$
en utilisant la commande rsh qui lance le xauth sur la machine A depuis la machine B.
6-4-4-d. Compter sur ssh pour l'autorisation▲
Aujourd'hui sur certains systèmes, on peut utiliser l'option -X de la commande sshSecure shell (ssh) permettant de passer outre la configuration (fastidieuse) des cookies :
$ ssh -X machine_distante
Password:
Une fois connectés sur la machine distante, les clients X utiliseront automatiquement le serveur de la machine locale et feront transiter les requêtes X en utilisant le cryptage de ssh.
6-4-5. Étude de cas : fond d'écran▲
Dans l'environnement X, on peut imposer une couleur à la fenêtre racine avec la commande xsetroot, par exemple :
$ xsetroot -solid black
$
met le fond d'écran à la couleur noire. Dans cette étude de cas, on se propose de mettre en fond d'écran une image tirée au hasard parmi une série. Pour ce faire, on utilisera le programme xloadimage. Si l'on dispose d'une image fond.jpg, on pourra la mettre en fond d'écran avec la commande :
$ xloadimage -border black -center -onroot fond.png
fond.jpg is a 1075x716 JPEG image, [...], Huffman coding.
Merging...done
Building XImage...done
$
Supposons maintenant que l'on dispose de plusieurs images dans un répertoire :
$ ls ~/photos/fonds
fond-00.png fond-02.png fond-04.png fond-06.png
fond-01.png fond-03.png fond-05.png fond-07.png
$
Pour choisir une image au hasard, on va d'abord compter le nombre d'images du répertoire et le stocker dans une variable :
$ nbf=$(ls -l ~photos/fonds/fond-??.png | wc -l)
$ echo $nbf
8
$
On peut ensuite choisir un nombre au hasard en exploitant la variable RANDOM et l'opérateur modulo du shell :
$ f=$[RANDOM%nbf]
$ echo $f
3
$
la variable RANDOM contient une valeur tirée aléatoirement entre 0 et 32 767(109) L'opérateur % renvoie le reste de la division entière. Par conséquent l'expression arithmétique $[RANDOM%nbf] renvoie un nombre tiré aléatoirement entre 0 et nbf-1. Il ne reste plus qu'à construire le nom du fichier à partir de ce nombre. Pour cela, on peut utiliser la commande printf fonctionnant comme celle du langage C :
$ printf "~/photos/fond/fond-%02d.png\n" $f
~/photos/fond/fond-03.png
$
Outre le fait que $RANDOM n'est pas aussi aléatoire qu'on le souhaiterait en particulier dans les bits de poids faible, cette variable ne fait pas partie de la norme Posix, mais est disponible dans les shells bash et ksh.
Voici enfin une possibilité de script rassemblant les commandes précédentes :
#!/bin/sh
# répertoire stockant les images
dirfonds
=
"
$HOME
/photos/fonds"
# nombre d'images dans ce répertoire
nbfonds
=
$
(
ls -l $dirfonds
/fond-??.png |
wc -l)
# numéro du fond tiré aléatoirement
nfondchoisi
=
$
(
echo $
[RANDOM%$nbfonds
])
# nom du fond tiré aléatoirement
fondchoisi
=
$
(
printf "
$dirfonds
/fond-%02d.png"
$nfondchoisi
)
# chargement en fond d'écran
xloadimage -display :0
-border black -center \
-onroot $fondchoisi
>
/dev/null
Il ne reste plus qu'à lancer ce script dans le fichier de démarrageComprendre le démarrage de la session X (le fichier .xsession), et dans la crontabLe service cron de l'utilisateur séduit par ce merveilleux fond d'écran dynamique. Par exemple :
$ crontab -l
0-59/15 * * * * ~/bin/fond.sh
$
changera de fond d'écran tous les quarts d'heure. Notez bien que ce cron n'aura de sens que si le système sur lequel vous vous connectez vous propose un serveur X…
L'option -display de la commande xloadimage dans le script est nécessaire, car au moment où le script est lancé par le daemon cron, la variable DISPLAY est vide. Vous aurez également noté qu'on redirige dans le fichier « trou noir », les bavardages du programme xloadimage, ceci pour éviter que le daemon cron ne nous les envoie par mail tous les quarts d'heure…
6-5. Installer des logiciels▲
Nous finirons ce chapitre par une présentation succincte de la manière d'installer des logiciels sur son propre compte. Cette activité peut en effet être vue comme la configuration de son environnement de développement, puisqu'on a parfois besoin d'installer des utilitaires pour son usage personnel sans exiger de l'administrateur qu'ils soient installés pour tous les utilisateurs. Les instructions primordiales sont les suivantes :
- lire la doc ! celle-ci se trouve généralement dans des fichiers portant les noms README, INSTALL, LISEZMOI, etc.
- maîtriser l'utilisation des outils d'archivageArchivage et de compression (gzip et tar) ;
- maîtriser l'utilisation de l'utilitaire makeMakefile dans le cas d'installation sous forme de source.
On considérera donc que le « package » binaire ou source à installer se présente sous forme d'une archive compressée et que l'utilisateur est capable de la décompacter dans un répertoire particulier.
6-5-1. Installer des binaires▲
Une fois l'archive décompressée, il faut suivre les instructions se trouvant dans le fichier décrivant l'installation. Certaines archives contiennent des scripts permettant de copier les fichiers dans des répertoires spécifiques de manière plus ou moins automatique. On peut toujours éditer ces scripts pour les adapter à ses besoins. En tout état de cause, l'installation de programme binaire consiste la plupart du temps à copier :
- un ou plusieurs fichiers exécutables dans un endroit spécifique ;
- des bibliothèques.
- des pages de manuels et autres fichiers info.
En supposant que le logiciel s'installe dans le répertoire ~/monsoft, il faudra s'assurer que le système puisse accéder à ces différents fichiers de la manière suivante :
-
mettre à jour la variable PATH :
Sélectionnezexport PATH=~/monsoft/bin:$PATH
-
mettre à jour la variable MANPATH :
Sélectionnezexport MANPATH=~/monsoft/man:$MANPATH
-
mettre à jour la variable LD_LIBRARY_PATH :
Sélectionnezexport LD_LIBRARY_PATH=~/monsoft/lib:$LD_LIBRARY_PATH
Dans le cas de « petits » utilitaires on peut se contenter d'installer les fichiers avec d'autres utilitaires, par exemple dans les répertoires :
- ~/bin pour les exécutables ;
- ~/man pour les pages de manuels ;
- ~/lib pour les bibliothèques dynamiques.
6-5-2. Installer des sources▲
L'installation de programmes sous forme de sources peut être plus délicate à cause des problèmes de portabilité entre les différentes versions d'unix. Lorsque l'archive est proposée sous forme de sources, elle fournit un Makefile contenant diverses informations que l'on peut adapter à son installation :
- le compilateur utilisé, ainsi que les options associées ;
- les répertoires d'installations (pour les binaires, le manuel, etc.)
- …
Ces informations sont proposées sous la forme de variablesVariables make. Une fois le Makefile adapté (le fichier INSTALL ou le Makefile lui-même contient des instructions qui guident le choix de ces options), il faut créer l'exécutable, généralement en lançant simplement la commande :
$ make
...
$
Puis il faudra lancer l'installation proprement dite des fichiers ; ce qui est généralement effectué grâce à la commande :
$ make install
...
$
encore une fois les Makefile peuvent être préparés de manière différente selon le logiciel à installer, il est donc impératif de lire les documentations fournies pour connaître les cibles exactes. À ce propos, la commande :
$ make -n install
...
$
vous permettra de simuler l'installation et d'avoir un aperçu des répertoires dans lesquels seront installés les fichiers.
Pour simplifier la vie des vaillants utilisateurs, le projet GNU a créé un utilitaire permettant d'adapter automatiquement le Makefile à votre système, ceci tout en gardant un certain degré de souplesse. Cet utilitaire se présente dans l'archive des sources sous la forme d'un script nommé configure :
$ ./configure
...
$
permet après un temps de scrutation de votre système de créer un Makefile reflétant les caractéristiques de l'unix sur lequel vous travaillez. Une fois le Makefile créé, les commandes décrites plus haut (make et make install) ont le même rôle.
Le script configure tient généralement compte du fait que le logiciel s'installera dans le répertoire /usr/local, ce qui est une pratique courante. Dans la mesure où vous n'avez généralement pas les droits d'accès à ce répertoire, vous pouvez spécifier la racine de l'installation, avec :
$ ./configure --prefix=$HOME/monsoft
...
$
qui configurera le Makefile pour que l'utilitaire soit installé avec comme racine ˜/monsoft. La commande ./configure --help vous donnera les autres options disponibles pour le package que vous installez.
6-5-3. Installer des paquets Debian▲
Ce qui suit vous sera utile uniquement si votre unix est un système gnu/LINUX et si celui-ci est installé via des paquets Debian. C'est le cas bien évidemment de la célèbre Debian, mais aussi de la star du moment : la distribution Ubuntu.
Les distributions de gnu/LINUX Debian et Ubuntu utilisent le même système de « paquets » pour installer les logiciels. Ce système permet de gérer les différentes versions à mettre à jour et d'inclure dans chaque paquet des scripts de préinstallation et postinstallation qui sont lancés, comme leur nom l'indique, avant et après l'installation des binaires(110) du paquet(111).
Dans son utilisation la plus courante, le principe de la gestion des paquets repose sur l'utilisation de dépôts accessibles depuis le réseau ou depuis des périphériques amovibles (cédérom, dvd…). Ces dépôts contiennent les versions officielles des paquets constituant la distribution. Il en existe des « miroirs » dans différents pays accélérant ainsi l'accès aux ressources. Vous devriez trouver sur votre système un fichier /etc/apt/sources.list dont voici ce que pourrait être un extrait :
$ cat /etc/apt/sources.list
[...]
deb http://ftp.fr.debian.org/debian/ lenny main
deb http://security.debian.org/ lenny/updates main contrib non-free
deb http://www.debian-multimedia.org lenny main
[...]
$
Dans la mesure où les fichiers stockés sur ces machines distantes évoluent, il est nécessaire de mettre à jour la liste des paquets sur votre système. Cette liste est conservée dans le fichier :
- /var/cache/apt/pgkcache.bin
Même s'il est fort probable que votre distribution mette à jour automatiquement par cron ce fichier, il n'est pas inutile de savoir qu'on peut explicitement rafraîchir ce fichier grâce à la commande :
apt-get update
Ensuite un certain nombre d'opérations classiques sont possibles en utilisant entre autres, cette même commande apt-get :
-
installation d'un paquet :
Sélectionnezapt-get install <nom_du_paquet>
-
effacement d'un paquet (y compris ses fichiers de configuration)
Sélectionnezapt-get -purge remove <nom_du_paquet>
-
mettre à jour toutes les paquets pour lesquels existe une nouvelle version :
Sélectionnezapt-get upgrade
-
chercher parmi les paquets (installés ou non) ceux qui correspondent à un motif particulier :
Sélectionnezapt-cache -names-only search <motif>
-
Le motif doit être saisi comme une expression régulièregrep et la notion d'expressions régulières. Par exemple tous les paquets commençant par « lib » et finissant par « pgsql » peuvent être listés grâce à la commande :
Sélectionnezapt-cache -names-only search '^lib.*pgsql$'
-
Pour chercher les paquets dont le nom ou la description contiendraient le mot « penguin » suivi du mot « race » :
Sélectionnezapt-cache search 'penguin.*race'
Pour finir cette présentation, sur les paquets Debian, il faut savoir qu'il existe un utilitaire de plus bas niveau permettant d'agir directement sur un paquet, c'est-à-dire sans passer un dépôt : la commande dpkg. Cette commande est d'ailleurs finalement appelée par la commande apt-get par exemple. Elle permet donc d'installer ou d'enlever un paquet, mais aussi d'extraire toutes les informations d'un fichier au format des paquets Debian.
6-6. Pour conclure▲
Vous êtes donc armé pour naviguer dans un système unix puisque vous avez maintenant les connaissances de base pour manipuler un éditeur de texte, configurer votre shell et votre environnement graphique. Ces connaissances, couplées avec celle du chapitre 5Chapitre 5 - Développer ! sur le développement, et du chapitre 4Chapitre 4 - Communiquer ! sur le réseau, vous donnent les bases nécessaires à l'exploration de ce système particulièrement vaste qu'est unix. Le chapitre qui suit vous donnera quelques pistes pour trouver les informations qui vous manquent.