Bash
: Soyez plus à l'aise dans votre coquille
Un
article du magazine "Linux mag France"
Vous
utilisez tous (peut être sans le savoir) le shell bash. Dans
cet article vous allez apprendre un certain nombre d'astuces qui
vous permettrons d'utiliser au mieux ce programme. C'est l'occasion
pour les nouveaux venus à Linux d'apprendre et aux vieux routards
de rafraîchir leurs souvenirs.
Le
shell sert d'interface entre le système d'exploitation et l'utilisateur.
Pour les utilisateurs qui sont venus récemment à Linux, le shell
est cette fenêtre principalement utilisée pour lancer les commandes
en mode texte. Pour les "vieux de la vieille", le shell
est l'unique, la vraie, la seule interface possible entre le noyau
et l'utilisateur ;-)
Avant la généralisation d'interfaces graphiques comme GNOME ou KDE,
les utilisateurs n'avaient guère d'autres possibilités pour exécuter
une commande que d'utiliser un shell. Aujourd'hui, cette interface
a tendance à être considérée comme obsolète et la plupart des nouveaux
utilisateurs n'en connaissent pas toutes les subtilités. Cet article
tente de réparer cette injustice malheureuse.
Historiquement,
le premier shell est dû à Steve Bourne au début des années 1970.
Un certain nombre d'autres shells ont depuis été écrits, mais le
plus courrament utilisé aujourd'hui est GNU bash (pour 'Bourne Again
SHell'). Il existe bien d'autres programmes ayant à peu de choses
près les mêmes fonctionnalités (ash, zsh, tcsh, pdksh, etc), mais
bash étant installé par défaut sur tous les systèmes Linux, c'est
celui-ci que nous allons étudier de plus près.
Maitrisez l'historique
Bash
contient un mécanisme d'hishorique extremement pratique. Lancez
simplement un shell, soit en vous loggant sur le système si vous
étes en mode texte, soit en cliquant dans votre barre de menu sur
l'icône qui représente soit un coquillage (si vous utilisez KDE),
soit un pingouin à coté d'un écran (si vous utilisez GNOME).
Il
est souvent pénible d'avoir à taper plusieurs fois de suite quasiment
la même commande à cause d'une faute de frappe. Pour cela, bash
offre un mécanique d'historique qui permet d'éditer les commandes
déjà entrées. Cet historique peut être utilisé grâce à plusieurs
méthodes.
Voyons de plus près chacune d'entre elles.
La
méthode de gestion d'historique la plus simple utilise les fléches
de directions. Essayez d'entrer successivement les trois commandes
suivantes dans un shell :
cd /
ls -al /etc/passwd
tail /etc/resolv.conf
Maintenant
tapez sur la flèche curseur 'haut'. La dernière commande est apparue
au prompt du shell. Tapez encore sur la fléche 'haut' et c'est la
commande ls qui devrait la remplacer. Pour repasser à la
commande suivante, tapez sur la fléche 'bas'. Il vous suffit maintenant
de taper sur entrée pour réexécuter cette commande. Notons au passage
que dans le cas où vous ne voulez ou ne pouvez pas utiliser les
fléches 'haut' et 'bas', vous pouvez utiliser à la place les combinaisons
de touches Ctrl-P (pour "Previous command") et
Ctrl-N (pour "Next command").
En plus de cette méthode séquentielle pour "reprendre"
des commandes, il existe un moyen d'effectuer une recherche dans
les commandes effectuées. Pour essayer cette méthode, tapez Ctrl-R.
Le prompt a été remplacé par la chaine (reverse-i-search)`'.
Si vous desirez retrouver la dernière commande qui contient la chaine
'etc', il vous suffit de taper cette chaîne et la commande 'tail
/etc/resolv.conf' apparaitra. A ce stade, vous pouvez soit
décider d'exécuter à nouveau cette commande en tapant sur entrée,
soit decider que vous vous vouliez en fait la dernière commande
opérant sur le fichier /etc/passwd. Dans ce dernier cas,
il suffit de continuer à taper, donc d'ajouter '/p', et
déjà le prompt devrait à la place montrer la commande ls -al
/etc/passwd.
Bash
permet également de référencer les commandes par numéro d'ordre.
Pour vous en convaincre, exécutez la commande "history".
Celle-ci affiche la liste des dernières commandes utilisées. Il
est possible que cette instruction liste des commandes qui ont été
utilisées lors de sessions précédentes. En effet, bash enregistre
la liste des commandes tapées durant la session dans un fichier
".bash_history" situé dans le répertoire racine
de l'utilisateur. Pour rappeler une commande, il suffit d'entrer
son numéro d'ordre précédé d'un point d'exclamation. Par exemple,
"!30" rappelle la trentième commande. Il est
également possible d'utiliser la syntaxe '!!' pour demander
la réexécution de la dernière commande entrée.
Ce mécanisme d'historique permet également de ne récupérer que certains
paramétres des dernières commandes :
# cat ~/articles/bash.html ~/articles/py4.html
[...]
# vi !-1:2
Cette
dernière notation indique à bash qu'il doit exécuter la commande
'vi' suivie du deuxième paramétre de la derniere commande.
L'utilisateur
averti pourra parfois avoir envie d'utiliser son éditeur favori
(que ce soit vim ou emacs) pour éditer la ligne de commande. Cela
est fort heureusement possible grâce à la commande 'fc'.
Celle-ci peut être utilisée avec plusieurs paramètres différents
qui permettent de gérer au mieux l'historique de votre session en
cours. Notons au passage que 'fc' n'est pas une commande que vous
pourrez trouver sur votre disque dur, c'est une commande interne
("built-in") du shell, au même titre que 'cd'
par exemple.
fc peut être invoqué aussi bien pour lister une partie de l'historique
:
fc -l -20 : affiche les 20 dernières commandes.
que pour l'éditer :
fc -e vi : édite la dernière commande tapée avec vi et exécute la
commande modifiée lors de la sortie de l'éditeur.
D'autre part, l'éditeur utilisé par fc par défaut peut
être spécifié une fois pour toutes en donnant à la variable FCEDIT
le nom de votre éditeur de prédilection.
Écrivez vos propres scripts
Si
vous avez tendance à utiliser souvent la même séquence de commandes,
l'écriture d'un script peut se réveler plus pratique que d'utiliser
le mécanisme d'historique. Un script est tout simplement une liste
de commandes shell enregistrées dans un fichier qui seront exécutées
ensemble lorsque le script sera appelé. Commençons par un exemple
simple; supposons que vous désiriez écrire un script qui soit capable
de remplacer une chaîne de caractères donnée par une autre dans
un fichier texte.
Commencez par enregistrer les lignes suivantes à l'aide de votre
éditeur de texte favori dans un fichier nommé 'script.sh'
:
#!/bin/sh
cp $1 /tmp/replace.$$
sed -e "s/$2/$3/g" < /tmp/replace.$$ > $1
Puis
exécutez la commande 'chmod +x script.sh' pour rendre le
script directement exécutable.
Pour
le tester, créez un fichier 'test.txt' contenant simplement la ligne
de texte :
Red Hat est la meilleure distribution Linux!
Maintenant,
testons si notre programme fonctionne correctement :
# ./script.sh test.txt "Red Hat" Debian
# cat test.txt
Debian est la meilleure distribution Linux!
#
Ça
marche! ;-)
Examinons
maintenant le code de notre script plus en détail :
La première ligne indique au noyau le nom de l'interpréteur à utiliser
pour exécuter le script, en l'occurence /bin/sh qui est
un lien vers /bin/bash.
La deuxième ligne est utilisée pour faire une copie de notre fichier
d'origine. A l'exécution, les variables $1, $2, $3, etc
sont substituées par les premier, deuxième et troisième paramètres
passés sur la ligne de commande.
La variable $$ est également spéciale : celle-ci correspond
au numéro de processus (PID) de l'instance du shell qui exécutera
le script. Cette variable est très souvent utilisée, comme elle
l'est ici, pour déterminer un nom de fichier temporaire.
La troisième et dernière ligne est celle qui fait réellement ce
que l'on attend du script, à savoir le remplacement de chaînes.
Le fichier temporaire est utilisé comme source de données et le
résultat de la substitution et remis dans le fichier d'origine.
Nous
allons maintenant essayer de rendre ce script un peu plus robuste.
En effet, si le nombre de paramètres passés est incorrect ou s'il
y a une erreur lors de la création du fichier temporaire, l'erreur
ne sera pas correctement détectée ce qui risque de laisser l'utilisateur
perplexe dans la mesure ou l'absence de message d'erreur est censé
indiquer un bon déroulement des opérations.
Pour
commencer, nous devons nous assurer que le nombre de paramètres
passés au script est bien correct.
Nous
allons préalablement définir une fonction dont le but est d'afficher
un message mentionnant les paramètres attendus par le programme
et de terminer l'exécution du script.
usage()
{
echo "Usage : script.sh fichier.txt
chaine1 chaine2"
exit -1
}
Maintenant,
on teste que les 3 paramètres existent et on exécute la fonction
usage le cas échéant.
[
-z "$1" -o -z "$2" -o -z "$3" ] &&
usage
Comme
vous l'avez probablement déjà deviné, l'opérateur '-o'
correspond au "ou logique", alors que '-z' retourne
la valeur vraie si la chaîne de caractères qui suit est vide.
Maintenant,
pour que notre programme soit vraiment beau, il ne reste plus qu'à
définir le nom du fichier temporaire dans une variable, plutôt que
de le désigner directement chaque fois que l'on en a besoin. En
effet, une des règles de base de la programmation stipule qu'une
définition ne doit jamais être faite à deux endroits différents,
ou si vous préférez, vous devez "factoriser" votre code
le plus possible.
Cela se fait simplement en ajoutant la définition suivante au début
du script :
tmp=/tmp/replace.$$
et par la suite on utilise $tmp pour faire référence
au nom du fichier temporaire.
Nous devons également tester qu'il n'existe pas déjà un fichier
ayant le même nom.
Pour cela, on effectue un test avec l'opérateur '-e' qui
teste l'existence d'un fichier :
if [ -e "$tmp" ]
then
echo "Le fichier $tmp existe deja."
exit -1
fi
Enfin,
la touche finale : on ajoute l'instruction 'set -e' au
début du script pour qu'il s'interrompe dès qu'une commande retourne
une valeur de retour non nulle, ce qui indique son échec (par exemple,
l'impossibilité de créer le fichier temporaire dans l'éventualité
de l'échec de la commande 'cp').
Et
voici la version finale de notre script :
#!/bin/sh
tmp=/tmp/replace.$$
if [ -f "$tmp" ]
then
echo "le fichier
$tmp existe deja."
exit -1
fi
usage()
{
echo Usage : script.sh
fichier.txt chaine1 chaine2
exit -1
}
[
-z "$1" -o -z "$2" -o -z "$3" ] &&
usage
cp
$1 $tmp
sed -e "s/$2/$3/g" < $tmp > test2.txt
Voilà,
maintenant vous devriez en savoir assez pour être à l'aise avec
la ligne de commande, ainsi qu'être capable d'écrire vos propres
programmes shell pour réaliser des tâches simples. Si vous désirez
en savoir plus sur le sujet (que nous n'avons qu'effleuré ici),
vous pourrez consulter les documents cités en références. Bons scripts!
_____________________________________
Utilisateur
de GNU/Linux depuis 1993, Vincent Renardias est activement impliqué
dans son développement depuis 1996 : Développeur de la distribution
Debian, auteur de la traduction Française de l'environnement GNOME,
créateur du groupe d'utilisateurs Linux de Marseille (PLUG). Il
continue aujourd'hui activement a promouvoir le système GNU/Linux
en tant que responsable technique de la société Echo (créatrice
du moteur de recherche www.voila.fr).
Vincent Renardias <vincent@echo.fr> |