Utiliser bash

Présentation de ce cours
Rubrique : Utilisation de GNU/Linux
Niveau : **
Audience : Utilisateur de GNU/Linux.
Lectures préalables : Aucune.
But : Présenter bash, le shell par défaut GNU/Linux, et indiquer comment l'utiliser.

Exécuter une commande | (Haut de page) |

bash est le shell le plus utilisé avec GNU/Linux. Le shell permet de donner des instructions au système en ligne de commande.

Lorsque l'on tape une instruction, le premier mot est la commande elle-même. Ensuite viennent les paramètres éventuels. Le shell va alors essayer de trouver à quoi la commande correspond dans l'ordre suivant.

Tout d'abord si la commande contient une spécification d'emplacement, le programme se trouvant dans ce répertoire est exécuté s'il s'y trouve et si l'utilisateur a les droits adéquats. Sinon une erreur est affichée.

Ensuite bash regarde quels alias sont définis. Un alias est un moyen d'exécuter une commande par un raccourci. Pour que par exemple le fait de taper mon_alias exécute ma_commande, il faudra déclarer l'alias comme ceci :

> alias mon_alias='ma_commande'

Les guillemets ne sont utiles que si la commande a des paramètres (c'est à dire qu'elle contient des espaces). Le contenu de ma_commande sera évalué selon le même schéma pour trouver le programme à exécuter.

Si on tape après :

> mon_alias paramètre1 paramètre2

Tout se passe comme si ma_commande avait été tapé à la place de mon_alias. Il va donc aussi avoir les paramètres.

Si aucun alias n'est trouvé, ce sont alors les fonctions qui sont examinées. Une fonction est un moyen de regrouper plusieurs commandes. Et de faire des traitements plus complexe qu'avec un alias. Une fonction se déclare comme ceci :

> function ma_fonction() { ma_commande1; ma_commande2; }

Pour la définition de la fonction, on peut omettre le mot-clé fonction ou les parenthèses, mais au moins un des deux doit être présent.

Le ; (point-virgule) permet de séparer les commandes et aussi de les terminer. A l'intérieur de la fonction, des variables positionnelles ($1, $2, ...) sont définies automatiquement par le shell. Elles correspondent aux paramètres passés à la fonction. Considérons l'exemple suivant :

> function mon_affichage { echo "SAIT : $1"; }

On aura alors le résultat suivant :

> mon_affichage Bonjour
SAIT : Bonjour

Dans le cas où aucune fonction correspondant n'existe, le shell consulte ses commandes intégrées (shell builtin commands). Avec bash, on peut citer comme exemple de commandes intégrées cd (pour changer le répertoire courant) ou echo vu précédemment.

Enfin le shell parcourt les répertoires contenus dans la variable d'environnement $PATH pour y chercher un programme du nom tapé. Si celui-ci est trouvé, il est exécuté, sinon une erreur est affichée.

Un exemple de variable $PATH :

> echo $PATH
/home/tian/bin:/usr/local/bin:/usr/bin:/bin

Si deux programmes avec le même nom se situent dans /usr/local/bin et /bin, c'est le premier qui sera exécuté.

En résumé voici l'ordre d'évaluation si la commande est exécutée sans spécification de chemin :

  • alias
  • fonction
  • commandes intégrées
  • exécutables dans un des répertoires de $PATH

Si tout cela échoue, un message d'erreur sera affiché. La commande type permet de savoir à quelle catégorie appartient une commande. Dans les deux premiers cas, on a la correspondance de l'alias ou de la fonction. Les commandes intégrées sont indiquées par un texte générique et pour le dernier cas, le chemin de l'exécutable est affiché.

Lorsque l'on exécute une commande, bash crée un sous-shell pour le lancer. C'est-à-dire que cela se passe comme si on avait lancé une nouvelle fois bash. Pour modifier ce comportement, on peut placer un . (point) en début de ligne. Cela provoquera alors l'exécution dans le shell courant. Exemple :

> . ma_commande

Pour terminer cette première partie, signalons que le shell peut aussi procéder à des développements de noms de fichiers avant l'exécution des programmes. Il y a pour cela une syntaxe relativement simple de motifs. bash va remplacer le motif par tous les noms de fichiers correspondant à celui-ci selon les règles suivantes :

  • * peut correspondre à n'importe quelle suite de caractères, y compris aucun caractère.
  • ? peut correspondre à n'importe quel caractère unique.
  • [ ] correspond à un des caractères spécifié entre les crochets. Une suite de caractères successifs est indiquée par un - (tiret) placé entre les bornes.

Par exemple [xX1-9]mod* sera remplacé par tous les noms de fichiers commençant par un x, un X ou n'importe quel chiffre, suivi par la chaîne mod puis ensuite n'importe quel chaîne de caractères. Cette substitution est effectuée avant l'exécution du programme qui recevra donc comme paramètres cette liste.

Historique des commandes | (Haut de page) |

bash conserve les dernières commandes tapées afin de pouvoir facilement les retrouver. Elles sont sauvegardées en mémoire pour le shell courant si plusieurs sont lancés. Et lorsque celui-ci est quitté, elles sont écrites dans le fichier .bash_history qui se trouve à la racine du répertoire personnel de l'utilisateur (~). Ce fichier est celui par défaut, son nom peut être changé par la variable d'environnement $HISTFILE. Le nombre de précédentes commandes sauvegardées en mémoire est défini par la variable $HISTSIZE (par défaut 500) et le nombre devant être sauvegardées dans le fichier par la variable $HISTFILESIZE (également 500 par défaut). Les commandes sont sauvegardées avant la substitution éventuelle faite (si des caractères *, ? ou [ ] sont présents).

Pour parcourir l'historique, il suffit d'utiliser les touches fléchées (à gauche du pavé numérique). La flèche vers le haut permet de parcourir les commandes dans l'ordre inverse de leur exécution et la flèche vers le bas dans l'autre sens. Peuvent également être utilisées respectivement les combinaisons Ctrl P (Previous) et Ctrl N (Next). Pour les habitués de l'éditeur de texte Emacs, ce sont les combinaisons de touches de ce logiciel qui peuvent être utilisées pour éditer les commandes entrées.

De même que dans cet éditeur, on peut rechercher parmi les commandes précédentes. Pour cela il faut taper Ctrl R (Touche Ctrl en bas du clavier puis en la maintenant, la touche R). Apparaît alors une invite permettant la recherche de la forme suivante :

(reverse-i-search)`':

Qui remplace alors l'invite de commande habituelle. La recherche se fait de manière incrémentale. C'est à dire qu'au fur et à mesure que l'on tape des caractères, la plus récente ligne de l'historique trouvée sera affichée. Pour interrompre la recherche, on peut taper Ctrl G ou une des touches fléchées (gauche et droite permettant alors de l'éditer). La touche Entrée permet d'exécuter la commande affichée.

Variables d'environnement | (Haut de page) |

Ces variables permettent de stocker des valeurs pour pouvoir les utiliser plus tard. Elles n'ont pas besoin d'être déclarées. bash les créera dès la première utilisation. Pour affecter à la variable VARIABLE la valeur VALEUR, on tapera :

> VARIABLE=VALEUR

Le signe = permet de faire l'affectation. Il est indispensable de ne pas mettre d'espace avant ou après ce signe, ce qui est une erreur fréquente.

VALEUR ne doit pas contenir d'espace non plus. Si on veut affecter une chaîne de caractères en comprenant, on utilisera des guillemets :

> PHRASE="une valeur avec des espaces"

Pour accéder ensuite à la valeur d'une variable, on préfixe son nom avec $ (dollar). Celui-ci est sensible à la casse. Le moyen le plus simple de tester la valeur d'une variable est d'utiliser la commande echo qui affiche ce qu'on lui passe en paramètre.

> echo $PHRASE
une valeur avec des espaces

On peut également accéder à la valeur d'une variable en rajoutant des accolades autour du nom, ce qui est parfois utile.

> phrase="une phrase avec des espace"
> echo ${phrase}s
une phrase avec des espaces

Sans les accolades, bash aurait essayé d'évaluer la variable $phrases

La définition d'une variable d'environnement, comme vu précédemment, limite sa visibilité au shell courant. C'est à dire que dans un sous-shell, on ne pourra pas accéder à sa valeur.

La commande export permet d'étendre la définition d'une variable aux autres shells créés à partir de celui courant (soit explicitement, soit en lançant une commande). Elle peut s'utiliser sur une variable déjà créée, ou l'initialisation peut être faite en même temps.

> variable_existante=valeur1
> export variable_existante
> export nouvelle_variable=valeur2

On remarquera que la variable n'est pas préfixée par le $ lors de l'appel à export. Si tel avait été le cas, ce serait la variable de nom valeur1 (inexistante dans cette exemple) qui aurait été exportée.

bash permet aussi d'avoir des variables tableaux. Celles-ci sont des tableaux associatifs. La clé pour y accéder peut être n'importe quelle chaîne de caractères. Par défaut ce seront des numériques commençant à 0. Les tableaux sont aussi créés automatiquement. Pour initialiser un tableau en une seule opération :

> tableau1=(valeur0 valeur1 valeur2)

On accède ensuite à un élément par ${tableau[clé]} où clé sera ici un nombre entre 0 et 2.

> echo ${tableau1[2]}
valeur2

On peut par cette même notation affecter une valeur à l'élément du tableau. Si on affecte la valeur à un élément qui n'existe pas encore, il sera créé. Il ne doit pas nécessairement être à la suite du dernier élément. On peut créer celui d'indice 5 sans que les 3 et 4 n'existent.

> ${tableau1[5]}=valeur5

Pour créer un tableau en n'utilisant pas les indices par défaut, on utilisera la syntaxe suivante :

> tableau2=([clé0]=valeur0 [clé1]=valeur1 [clé2]=valeur2)

Où les clés peuvent être n'importe quelles chaînes de caractères. A un tableau créé avec les index numériques par défaut, on peut très bien ajouter un élément dont la clé est une chaîne de caractères.

Utilisation des guillemets | (Haut de page) |

Il y a 3 types de guillemets à utiliser.

En premier lieu il y a les guillemets doubles ("). Leur rôle est de regrouper plusieurs chaînes de caractères séparées par des espaces. Si un programme accepte un seul paramètre, l'exécution suivante génèrera une erreur :

> ma_commande une phrase en paramètre
Erreur : ma_commande n'accepte qu'un paramètre

Car là on lui a passé 4 paramètres. Alors que dans le cas suivant, ma_commande recevra un seul paramètre contenant la chaîne complète :

> ma_commande "une phrase en paramètre"
Résultat de ma_commande

Cela est aussi utile pour affecter à une variable une chaîne de caractères comprenant des espaces.

Si une variable est contenue entre les doubles guillemets (avec le $ devant le nom), elle est remplacée par sa valeur.

Les guillemets simples (') jouent le même rôle. La différence vient du fait qu'aucune substitution de variable n'est effectuée. La chaîne comprise entre ' ' conservera les caractères $

Les derniers sont les guillemets inversés (`). Ils permettent d'exécuter une commande. La chaîne comprise entre ` ` vaudra le résultat retourné par la commande. Les variables sont remplacées par leurs valeurs avant l'évaluation de la commande. Cela est souvent utilisé pour affecter un résultat à une variable. Pour l'exemple suivant, la commande intégrée pwd permet d'afficher le répertoire courant.

> REPERTOIRE=`pwd`
> echo $REPERTOIRE
/home/tian

Il existe une notation équivalente à la précédente. La commande peut être placée entre $( ). L'exemple devient alors :

> REPERTOIRE=$(pwd)

Expressions arithmétiques | (Haut de page) |

On peut facilement évaluer des expressions arithmétiques avec bash. Pour cela, on utilise la notation $(( )) qui sera remplacée par le résultat du calcul mathématique. Voici les opérations pouvant être utilisées par ordre de priorité inverse (extrait de la page de manuel de bash) :

  • - + plus et moins unaire
  • ! ~ négations logique et binaire
  • * / % multiplication, division, reste
  • + - addition, soustraction
  • << >> décalage arithmétique à gauche et à droite
  • <= >= < > comparaisons
  • == != égalité et différence
  • & ET binaire
  • ^ OU exclusif binaire
  • | OU binaire
  • && ET logique
  • || OU logique
  • = *= /= %= += -= <<= >>= &= ^= |= assignations

bash effectuera le remplacement par la valeur avant l'exécution des commandes éventuelles. La commande suivante est une erreur :

> $((variable=3+2))
bash: 5: command not found

La variable contiendra bien la valeur 5 à la suite de cette action. Mais bash a remplacé l'expression par sa valeur, donc tout se passe comme si on avait uniquement tapé 5 à l'invite (qui se trouve être un programme inconnu).

Une autre notation est possible en mettant $[ ] autour de l'expression à la place de $(( )).

Redirections | (Haut de page) |

Par défaut un programme lit depuis le clavier et écrit ses résultats sur l'écran. On parle d'entrée et sortie standards qui sont tous deux des flux. Mais ce comportement peut être modifié à l'aide des redirections qui vont modifier les entrée et sortie du programme sans qu'il ne s'en rende compte.

Pour que le résultat d'un programme soit enregistré dans un fichier plutôt qu'affiché, il faut utiliser > suivi du nom du fichier. ls sans argument permet d'afficher la liste des fichiers et répertoires présents dans le répertoire courant. Après cette commande :

> ls > liste_fichiers

Le fichier liste_fichiers contiendra ce que l'on aurait vu s'afficher dans le terminal sans la redirection. Si le fichier existait, il est détruit et remplacé par le nouveau contenu. Pour ajouter des données à la fin d'un fichier existant, on utilisera >> à la place :

> ls >> liste_fichiers

De la même manière, on peut dire à un programme de lire depuis un fichier plutôt que depuis le clavier. Cela se fait à l'aide de < suivi du nom du fichier. Le programme cat sans argument affiche ce qu'il lit sur son entrée standard.

> cat < liste_fichiers

Provoquera l'affichage du fichier précédent. Cela est utile pour automatiser le traitement fait par un programme interactif. On peut placer dans un fichier la liste des commandes à lui faire exécuter, et ensuite lui passer en redirigeant son entrée standard depuis ce fichier.

Avec << on peut indiquer en une seule fois tout ce qui doit être passé en entrée puis lancer l'exécution ensuite. Après << il doit y avoir une chaîne de caractères quelconques. Une ligne comprenant uniquement cette chaîne indiquera la fin des entrées. Il est donc important de la choisir de sorte à ce qu'elle n'apparaisse pas dans la liste de données.

> cat <<DELIMITEUR
> ligne 1
> ligne 2
> DELIMITEUR
ligne 1
ligne 2

On peut enfin rediriger la sortie standard d'un programme vers l'entrée standard d'un autre, cela afin de les enchaîner et/ou de filtrer les résultats. Cela se fait à l'aide de | appelé pipe en anglais ou tube en français. grep est un outil permettant de ne garder que les lignes comportant un certain motif.

> ls | grep txt

Cet exemple permet de n'afficher que les fichiers et répertoires comprenant txt dans leur nom.

Pour terminer ceci, citons un outil utile, tee. Il permet de dupliquer un flux. Il redirige ce qu'il reçoit en entrée à la fois dans un fichier passé en paramètre et sur sa sortie. Ceci sert lorsqu'une longue commande est exécutée et que l'on souhaite sauvegarder les résultats tout en les examinant éventuellement au fur et à mesure. Exemple :

> ls | tee liste_fichiers