Exécution et nomenclature de programmes sous UNIX/Linux
par Benoit, 2014-05-14

Discutons du système de recherche d’un programme à exécuter sous UNIX/Linux, et comment mettre en place un programme muni d’un nom voulu.

Recherche d’un programme à exécuter: la variable PATH

Le shell sous UNIX/Linux est le programme typiquement utilisé pour lancer un l’exécution d’un programme. Il s’agit d’un interpréteur de langage de programmation dont les routines peuvent être simplement définies comme des programmes externes.

Par conséquent, le shell doit avoir un mécanisme pour identifier où se trouvent ces routines, ces commandes qui ont une sémantique sur un système donné. La convention est qu’un petit nombre de répertoires sur le système peuvent contenir des programmes exécutables. La plupart des systèmes utilisent les suivants, au minimum:

  • /bin
  • /sbin
  • /usr/bin
  • /usr/sbin
  • /usr/local/bin
  • /opt/bin

La liste de ces répertoires pouvant contenir un programme est stockée dans la variable d’environnement PATH du shell: chaque répertoire y est séparé des autres par le caractère deux-points (:). Par exemple, chez moi:

$ echo $PATH
/home/hamelin/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Tout programme présent dans l’un des répertoires listés dans la variable PATH peut être invoqué depuis le shell, sans décoration. Lorsque l’invocation d’un programme commence par un caractère approprié, le shell capture le nom et le recherche dans chacun des répertoires de PATH, à tour de rôle et dans l’ordre; il exécute le premier programme qu’il trouve qui correspond à ce nom.

Naturellement, on peut changer la valeur de PATH. Le fichier de configuration à modifier dépend du shell. Dans le cas du shell bash, la définition de PATH du système se trouve dans /etc/profile; on peut se faire une version modifiée pour soi en ajoutant une redéfinition de PATH dans l’un des fichiers .bashrc ou .profile dans son répertoire de base. Typiquement, on ajoute des répertoires au début ou à la fin de la valeur de base, ainsi:

export PATH="<repertoires fouilles avant>:$PATH:<repertoires fouilles apres>"

Exécuter un programme hors des répertoires de PATH

Il est également possible d’exécuter un programme se trouvant hors des répertoires listés dans PATH. Il faut alors indiquer au shell où se trouve se programme. Ainsi, pour la plupart des shells, si le premier mot d’une ligne de commande contient une barre oblique (/), le shell considère qu’on donne le chemin d’accès vers le programme à exécuter. Si ce chemin commence par /, il est absolu; sinon, il est relatif au répertoire courant du shell. Certains shells forcent d’ailleurs ces chemins relatifs à spécifier d’abord le répertoire courant, de sorte que la ligne de commande doive commencer par un point (.). Quelques exemples:

$ /usr/lib/programme
$ ./programme_dans_le_repertoire_courant
$ ./programme/a/moi
$ programme/a/moi    # Ne fonctionne pas sur tous les shells.

Le hashbang

Si c’est le shell qui détermine trouver un programme à exécuter, c’est le noyau du système d’exploitation qui détermine comment l’exécuter. Les noyaux POSIX (UNIX, Linux, etc.) admettent deux types de programmes directement exécutables:

  1. Les binaires (ELF, Mach-O, etc.)
  2. Les scripts

Les premiers sont des programmes compilés sous forme binaire, typiquement à l’aide d’un compilateur et/ou d’un assembleur. Les seconds sont des programmes encodés sous la forme de fichiers texte, qui sont interprétés. L’interpréteur doit se trouver quelque part sur le système. On indique où trouver l’interpréteur à l’aide de la première ligne du fichier, où le chemin d’accès vers l’interpréteur est précédé des caractères #! (dièse = hash; point d’exclamation = bang; #! = hashbang).

#!/bin/bash        # Script de *shell*
#!/usr/bin/python  # Programme Python
#!/usr/bin/perl    # Programme Perl (beurk)

Que le programme soit un binaire ou un script, pour que le noyau accepte de l’exécuter, il doit être muni du droit d’exécution. Le compilateur donne ce droit au binaire qu’il produit; en revanche, lorsqu’on écrit un script, on doit donner ce droit soi-même. On le fait grâce à la commande chmod:

$ chmod +x mon_script
$ ./mon_script

Type de fichier et script de lancement

Les scripts sont typiquement construits à l’aide d’un éditeur de texte, qui procure plusieurs services appropriés au langage pour assister la programmation (coloration lexicale, auto-indentation…). Les éditeurs qui valent la peine d’être appris (e.g. Vim, Emacs) peuvent déterminer le type d’un fichier en utilisant l’extension du nom du fichier (.py, .rb, .sh…) ou en utilisant la ligne hashbang discutée ci-haut.

Malheureusement, plusieurs éditeurs plus amicaux envers les débutants sont moins intelligents: ils n’arrivent à identifier le type de programme qu’en utilisant l’extension du script. Cela complique la nomenclature d’un script: on désire exécuter un script comme une commande, sans nécessairement taper l’extension. Garder l’extension du script est un problème d’interface usager.

Pour contourner ce problème, on peut utiliser un script de lancement. Il s’agit d’un script de shell très petit qui permet de mettre en oeuvre l’interpréteur pour un programme plus complexe, qu’on rédige dans un fichier muni de l’extension appropriée. Par exemple, j’ai un programme Python que je dois nommer monprog.py. Dans le même répertoire, j’ajoute alors le script suivant, que je sauvegarde sous le nom monprog:

#!/bin/bash
python monprog.py $@

La variable d’environnement $@ désigne l’ensemble des paramètres de ligne de commande passés au script monprog; ils sont donc repassés au programme Python. Pour permettre l’exécution, je donne le droit d’exécution au script de lancement:

$ chmod +x monprog

Supposons que le code dans monprog.py soit:

import sys
print "Hello world!"
for arg in sys.argv[1:]:
    print arg

Alors, exécutons ce programme à l’aide du script de lancement:

$ ./monprog asdf 56 qwerty
Hello world!
asdf
56
qwerty
Commentaires