OVH Cloud OVH Cloud

variable PATH dans des scripts

94 réponses
Avatar
Kevin Denis
Bonjour,

je suis en train de mettre à jour différents scripts afin de les
adapter à différents environnements.

De manière générale (et c'est une question plus large), je vois
souvent des scripts démarrer par une définition des binaires utilisés,
comme par exemple:
#! /bin/sh
LS=/bin/ls
WC=/usr/bin/wc
echo le nombre de fichier est `LS|WC`

Ma première question est la suivante, pourquoi utiliser une définition
littérale alors que l'on peut utiliser PATH?
#! /bin/sh
PATH=/bin:/usr/bin
echo le nombre de fichier est `ls|wc`

Ma seconde question, plus spécifique à mon cas, puisque selon
l'architecture les binaires sont dans des lieux différents:
Mieux vaut il faire
#! /bin/sh
PATH=/opt/bin:/bin etc..

ou bien:
#! /bin/sh
if [ test archi ] then
LS=/bin/ls
else
LS=/opt/bin/ls
fi

etc..

Merci.
--
Kevin

10 réponses

Avatar
Stephane CHAZELAS
2008-05-27, 01:30(+00), Vincent Lefevre:
Dans l'article ,
Stephane CHAZELAS écrit:

Tous les shells standard Unix ont ce cache et la commande "hash"
qui va avec (c'est une "XSI extension" dans SUSv3).
[...]


ay:~> sh
sh-3.1$ ls foo
ls: cannot access foo: No such file or directory
sh-3.1$ ln -s /bin/true bin/ls
sh-3.1$ ls foo
sh-3.1$ rm bin/ls
sh-3.1$ exit

Dans le premier cas (bash exécuté en tant que bash), le shell ne voit
pas le nouveau ls (dans un répertoire situé avant dans le $PATH) à
cause du cache. Dans le second cas (bash exécuté en tant que sh), le
shell voit le nouveau ls, donc pas de cache.


Ca ressemble a un bug dans ton sh, a moins que tu n'aies
un SHELLOPTS dans ton environment.

Je n'ai pas ce probleme avec bash 3.2.

Que te dit

strace -f sh -c 'ls;ls' 2>&1 | grep /ls

?

C'est d'autant plus important que les scripts shell portables
commencent par #!/bin/sh et non #!/bin/bash, et que $SHELL vaut
généralement /bin/sh.


Il n'y a aucune guarantie que /bin/sh soit un shell POSIX.

$SHELL, c'est pour que les applications sachent quel shell
interactif l'utilisateur souhaite, donc typiquement, c'est
/bin/zsh ;)


--
Stéphane


Avatar
Vincent Lefevre
Dans l'article <483bc036$0$26595$,
Nicolas George <nicolas$ écrit:

Sur un système correctement conçu, ce n'est pas un problème : on peut très
bien compiler un programme avec « -lreadline » et obtenir un binaire qui
dépend ensuite de libeditline.so.42. C'est précisément à ça que sert le
SONAME.


En fait, sous Mac OS X, le problème se pose essentiellement au niveau
de la compilation (le chemin complet de la bibliothèque se trouve dans
l'exécutable). Mais pour compiler, on est bien obligé de spécifier le
chemin vers la bonne bibliothèque. Je ne sais plus avec quel logiciel,
mais il est arrivé que le compilation se fasse avec les headers de
l'autre bibliothèque readline.

Maintenant, le SONAME ne change pas quand on compile avec des options
de compilation différentes. Là encore, on a besoin de spécifier les
chemins, par exemple, suivant qu'on veuille utiliser une version avec
débuggage mais lente ou une version rapide. Et sous Linux, pas seulement
à la compilation: il y a généralement besoin du LD_LIBRARY_PATH.

ncurses est binairement compatible avec curses.


Sous les systèmes où curses = ncurses, oui. Sur les autres (e.g. Solaris),
pas forcément.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

Avatar
Vincent Lefevre
Dans l'article ,
Stephane CHAZELAS écrit:

Ca ressemble a un bug dans ton sh, a moins que tu n'aies
un SHELLOPTS dans ton environment.


Non, pas de SHELLOPTS à ma connaissance.

Je n'ai pas ce probleme avec bash 3.2.

Que te dit

strace -f sh -c 'ls;ls' 2>&1 | grep /ls

?


ay:~> strace -f sh -c 'ls;ls' 2>&1 | grep /ls
stat64("/home/lefevre/bin/ls", 0x7f9e8798) = -1 ENOENT (No such file or directory)
stat64("/home/lefevre/wd/www/Admin/ls", 0x7f9e8798) = -1 ENOENT (No such file or directory)
stat64("/usr/local/bin/ls", 0x7f9e8798) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/ls", 0x7f9e8798) = -1 ENOENT (No such file or directory)
stat64("/bin/ls", {st_mode=S_IFREG|0755, st_size4704, ...}) = 0
stat64("/bin/ls", {st_mode=S_IFREG|0755, st_size4704, ...}) = 0
[pid 23493] execve("/bin/ls", ["ls"], [/* 99 vars */]) = 0
stat64("/bin/ls", {st_mode=S_IFREG|0755, st_size4704, ...}) = 0
stat64("/home/lefevre/bin/ls", 0x7f9e87b8) = -1 ENOENT (No such file or directory)
stat64("/home/lefevre/wd/www/Admin/ls", 0x7f9e87b8) = -1 ENOENT (No such file or directory)
stat64("/usr/local/bin/ls", 0x7f9e87b8) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/ls", 0x7f9e87b8) = -1 ENOENT (No such file or directory)
stat64("/bin/ls", {st_mode=S_IFREG|0755, st_size4704, ...}) = 0
stat64("/bin/ls", {st_mode=S_IFREG|0755, st_size4704, ...}) = 0
[pid 23494] execve("/bin/ls", ["ls"], [/* 99 vars */]) = 0

On voit bien qu'il ne cache pas l'emplacement du ls. Pour info:

ay:~> sh --version
GNU bash, version 3.1.17(1)-release (powerpc-unknown-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

Idem avec:

GNU bash, version 3.1.17(1)-release (x86_64-pc-linux-gnu)

En revanche, pas de problème avec:

GNU bash, version 3.2.39(1)-release (x86_64-pc-linux-gnu)

sur une autre machine (mais toutes sous une des Debian). C'est
peut-être une nouveauté de bash 3.2, mais ce n'est pas indiqué
dans le fichier NEWS. Je ne vois rien non plus de spécial dans
le changelog de Debian.

C'est d'autant plus important que les scripts shell portables
commencent par #!/bin/sh et non #!/bin/bash, et que $SHELL vaut
généralement /bin/sh.


Il n'y a aucune guarantie que /bin/sh soit un shell POSIX.


Je sais, mais portable != POSIX (e.g. les scripts sh des autotools
sont aussi censés fonctionner avec le /bin/sh de Solaris).

$SHELL, c'est pour que les applications sachent quel shell
interactif l'utilisateur souhaite, donc typiquement, c'est
/bin/zsh ;)


Moi j'ai SHELL à zsh, mais comme tu le dis, c'est pour les shells
interactifs essentiellement. Les autotools (par exemple) fixent
typiquement SHELL à /bin/sh dans le Makefile, qui sera utilisé
pour les bouts de shell qui y sont inclus. De même les scripts
générés utilisent /bin/sh. La fonction system() utilise /bin/sh,
etc. /bin/sh est un peu partout.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Vincent Lefevre
Dans l'article ,
Stephane CHAZELAS écrit:

Ben justemement, pour que PATH soit correct pour les scripts
des utilisateurs, il faut bien que quelquechose dans le systeme
le definisse. Et c'est en general les init scripts.


Mais la plupart des init scripts servent à lancer des démons et
leur environnement ne servira pas à l'utilisateur.

Typiquement, le PATH que les cron jobs heritent est le PATH
definit dans /etc/init.d/cron ou un de ses ancetres.


Sous Debian, on a:

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

dans le /etc/crontab et /etc/init.d/cron ne définit pas de $PATH.
Le /etc/init.d/cron va utiliser le PATH de ses ancêtres, mais les
jobs lancés par cron utiliseront le PATH du /etc/crontab.

D'autre part, il se peut que root ait à lancer cron à la main.
Garder le PATH du shell parent n'est pas forcément une bonne idée...

Maintenant, il y a aussi:
- le PATH des utilisateurs normaux,
- le PATH des super-utilisateurs quand ils se logguent
- le PATH de cron
- le PATH de xinetd/inetd
- le PATH par default du systeme
- le PATH de compatibilite avec tel ou tel standard (par
exemple, sous Solaris, faut faire un "getconf PATH" dans le
bon environnement (gueh!?) pour avoir des outils conformes
sinon par defaut on a les outils des 1980s.

C'est pas forcement toujours rose et propre.


Je suis d'accord. Mais fixer PATH est souvent nécessaire en pratique
pour être sûr d'avoir un environnement propre et les meilleures
conditions de sécurité. Tout dépend du contexte.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

Avatar
Stephane CHAZELAS
2008-05-27, 12:18(+00), Vincent Lefevre:
[...]
Moi j'ai SHELL à zsh, mais comme tu le dis, c'est pour les shells
interactifs essentiellement. Les autotools (par exemple) fixent
typiquement SHELL à /bin/sh dans le Makefile, qui sera utilisé
pour les bouts de shell qui y sont inclus.


Ca, c'est autre chose, le $SHELL de make est different du $SHELL
de l'environnement. Typiquement, et POSIX le dit clairement,
l'un et l'autre ne doivent pas deteindre sur each other
(j'arrive pas a trouver la tournure francaise (?)).

De même les scripts
générés utilisent /bin/sh. La fonction system() utilise /bin/sh,
etc. /bin/sh est un peu partout.
[...]


Pas forcement, system() utilise le sh conforme au standard
auquel system() conforme. Sous Solaris, system() peut appeler
/usr/xpg4/bin/sh ou /usr/xpg6/bin/sh or /bin/sh suivant les
options de compilation. Sur un systeme POSIX, system() utilisera
un sh POSIX, generalement /bin/sh.

--
Stéphane

Avatar
Vincent Lefevre
Dans l'article ,
Stephane CHAZELAS écrit:

2008-05-27, 12:18(+00), Vincent Lefevre:
[...]
Moi j'ai SHELL à zsh, mais comme tu le dis, c'est pour les shells
interactifs essentiellement. Les autotools (par exemple) fixent
typiquement SHELL à /bin/sh dans le Makefile, qui sera utilisé
pour les bouts de shell qui y sont inclus.


Ca, c'est autre chose, le $SHELL de make est different du $SHELL
de l'environnement. Typiquement, et POSIX le dit clairement,
l'un et l'autre ne doivent pas deteindre sur each other
(j'arrive pas a trouver la tournure francaise (?)).


Effectivement la doc de GNU make n'est pas très bien faite:

6.9 Variables from the Environment
=================================
Variables in `make' can come from the environment in which `make' is
run. Every environment variable that `make' sees when it starts up is
transformed into a `make' variable with the same name and value.
However, an explicit assignment in the makefile, or with a command
argument, overrides the environment. [...]

Le "Every" est incorrect. Cependant cette exception concernant SHELL
est mentionnée tout à la fin de cette section:

Such problems would be especially likely with the variable `SHELL',
which is normally present in the environment to specify the user's
choice of interactive shell. It would be very undesirable for this
choice to affect `make'; so, `make' handles the `SHELL' environment
variable in a special way; see *Note Choosing the Shell::.

et là:

5.3.1 Choosing the Shell
------------------------

The program used as the shell is taken from the variable `SHELL'. If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.

Unlike most variables, the variable `SHELL' is never set from the
environment. This is because the `SHELL' environment variable is used
to specify your personal choice of shell program for interactive use.
It would be very bad for personal choices like this to affect the
functioning of makefiles. *Note Variables from the Environment:
Environment.

Maintenant, je me demande pourquoi les autotools fixent explicitement
SHELL à /bin/sh dans le Makefile. Par simplicité? À cause de certains
"make" qui n'auraient pas ce comportement demandé par POSIX?

De même les scripts
générés utilisent /bin/sh. La fonction system() utilise /bin/sh,
etc. /bin/sh est un peu partout.
[...]


Pas forcement, system() utilise le sh conforme au standard
auquel system() conforme.


Oui, je pensais à Linux (c'était en réponse au problème que j'avais
mentionné avec le /bin/sh sur ma machine).

Sous Solaris, system() peut appeler /usr/xpg4/bin/sh ou
/usr/xpg6/bin/sh or /bin/sh suivant les options de compilation. Sur
un systeme POSIX, system() utilisera un sh POSIX, generalement
/bin/sh.


Et sur les systèmes non Unix (puisque system() est d'abord une
fonction C standard), ça pourra être encore autre chose...

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Nicolas George
Vincent Lefevre wrote in message
<20080527114229$:
En fait, sous Mac OS X, le problème se pose essentiellement au niveau
de la compilation (le chemin complet de la bibliothèque se trouve dans
l'exécutable).


Ça m'a l'air assez grotesque, ce truc.

Plus j'entends parler de macos x, moins j'ai envie de l'utiliser.

Mais pour compiler, on est bien obligé de spécifier le
chemin vers la bonne bibliothèque.


Compiler est une opération technique et relativement exceptionnelle, et à ce
titre peut tout à fait nécessiter des ajustements.

par exemple, suivant qu'on veuille utiliser une version avec
débuggage mais lente ou une version rapide.


Pareil : débugger, c'est une opération relativement exceptionnelle.

Sous les systèmes où curses = ncurses, oui. Sur les autres (e.g. Solaris),
pas forcément.


Je crois bien que si : ncurses fournit la même ABI que la vielle libtermcap.
Si ce n'était pas le cas, le lien symbolique serait nuisible.

Avatar
Vincent Lefevre
Dans l'article <483c42b6$0$12934$,
Nicolas George <nicolas$ écrit:

Vincent Lefevre wrote in message
<20080527114229$:
En fait, sous Mac OS X, le problème se pose essentiellement au niveau
de la compilation (le chemin complet de la bibliothèque se trouve dans
l'exécutable).


Ça m'a l'air assez grotesque, ce truc.


Cela a ses avantages (e.g. pas besoin de LD_LIBRARY_PATH), et il
y a toujours la possibilité d'overrider le chemin (e.g. en cas de
déplacement des bibliothèques). C'est AMHA plus propre que sous
Linux.

Plus j'entends parler de macos x, moins j'ai envie de l'utiliser.

Mais pour compiler, on est bien obligé de spécifier le
chemin vers la bonne bibliothèque.


Compiler est une opération technique et relativement exceptionnelle,
et à ce titre peut tout à fait nécessiter des ajustements.


Ce n'est pas exceptionnel, ça arrive tous les jours.

par exemple, suivant qu'on veuille utiliser une version avec
débuggage mais lente ou une version rapide.


Pareil : débugger, c'est une opération relativement exceptionnelle.


Ce n'est pas seulement pour du débuggage "actif". On peut vouloir
utiliser une version d'une bibliothèque qui contient une vérification
complète des assertions, par mesure de sécurité.

Sous les systèmes où curses = ncurses, oui. Sur les autres (e.g. Solaris),
pas forcément.


Je crois bien que si : ncurses fournit la même ABI que la vielle libtermcap.
Si ce n'était pas le cas, le lien symbolique serait nuisible.


En tout cas il y avait des problèmes.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Nicolas George
Vincent Lefevre wrote in message
<20080528025400$:
Cela a ses avantages (e.g. pas besoin de LD_LIBRARY_PATH),


Un Unix moderne correctement configuré n'a pas besoin de LD_LIBRARY_PATH, à
la base.

C'est AMHA plus propre que sous
Linux.


Est-ce qu'on peut avoir ta vision de ce qui se passe « sous Linux » ?

Ce n'est pas seulement pour du débuggage "actif". On peut vouloir
utiliser une version d'une bibliothèque qui contient une vérification
complète des assertions, par mesure de sécurité.


Ça reste quand même quelque chose d'extrêmement particulier.

Avatar
Thierry B.
--{ Nicolas George a plopé ceci: }--

Cela a ses avantages (e.g. pas besoin de LD_LIBRARY_PATH),


Un Unix moderne correctement configuré n'a pas besoin de LD_LIBRARY_PATH, à
la base.

Pas dans tous les cas de figure. C'est souvent très utile quand

tu as plusieurs yusers qui font du bricolage un peu avancé.
Ou quand tu as de vieilles application que la flemme t'empêche
de ré-adapter à une version récente d'une bibliothêque.

Ce n'est pas seulement pour du débuggage "actif". On peut vouloir
utiliser une version d'une bibliothèque qui contient une vérification
complète des assertions, par mesure de sécurité.


Ça reste quand même quelque chose d'extrêmement particulier.


Pas pour tout le monde.

--
David Lightman: Is this a game or is it real?
Joshua: What's the difference?
David Lightman: Oh, wow.