Pour mener à bien une compilation, nous avons besoin de définir toute une série de variables d'environnement. Les définitions de ces variables se trouvent par exemple dans un fichier nommé def-var:
Si nous exécutons def-var dans un terminal et que nous regardons ensuite ce qu'il en est au niveau des variables d'environnement existant dans le terminal, rien n'est changé.
Alors comment procéder? Taper toutes ces commandes?
Non, bien sûr: il existe une autre méthode.
Bon, reprenons en partant d'un fichier un peu plus ludique: le fichier bjr:
situé dans /home/toto/test.
Ce fichier contient toute une série de commandes.
Elles sont là, déjà écrites dans le fichier! Alors pourquoi les retaper?
Il suffit d'indiquer à bash que bjr constitue une source de commandes:
L'output de la commande echo est affiché en premier. Puis la commande "read moi" provoque l'affichage du curseur: le système est en attente de ce que nous allons taper au clavier afin de le mettre dans la variable moi:
Terminons la saisie par un appui sur ENTER:
Tapons effectivement à l'écran la première commande de bjr:
Le résultat est le même: 2849 est le pid du shell bash dans lequel nous sommes et 2838 celui de son processus parent (par exemple konsole ou gnome-terminal)
Lorsque bjr est sourcé, tout se passe comme si les commandes qu'il contient étaient tapées à l'écran. Ainsi la variable moi est maintenant définie dans le shell bash (pid 2849) avec la valeur "Ahuri".
Le mot "source" étant très long (et donc fatiguant à taper), il est le plus souvent remplacé par un point ("."):
Nous constatons que la variable moi est bel et bien définie (elle contient le mot "Ahuri") avant même l'exécution de la commande read
Et si nous exécutions bjr en tapant tous simplement son nom, comme pour n'importe quelle commande?
Problème:
C'est normal, bjr n'est pas trouvé car /home/toto/test ne figure dans la variable d'environnement PATH qui contient l'ensemble des répertoires où le système recherche les commandes.
Par curiosité, examinons le contenu de PATH:
/home/toto/test n'y figure évidemment pas, mais bien à toutes fins utiles /home/toto/bin.
Ainsi nous pourrions créer le lien symbolique qui convient.
En fait c'est la même chose:
Nous affichons d'abord les inodes des différents fichiers du dossier (y compris les fichiers cachés). En faisant une recherche sur l'inode 1717900 nous voyons que le fichier "." n'est autre que le dossier dans lequel on se trouve (/home/toto/test).
Ceci est bien connu et a déjà été expliqué dans un autre billet.
Le point (.) peut donc être mangé à plusieurs sauces.
Résumons:
. bjr : le point remplace la commande "source". bjr sera sourcé.
./bjr : le point remplace (ici) /home/toto/test. bjr sera exécuté.
Procédons à l'exécution (!):
Nouveau problème! Et oui: personne n'a le droit d'exécuter ce fichier, même pas le root.
Avant de procéder il faut d'abord donner le droit d'exécution sur bjr (avec la commande chmod +x bjr):
Intéressons nous à ce que vaut maintenant la variable moi dans le shell bash de base:
C'est encore la valeur résultant du "read" lorsque bjr a été sourcé pour la deuxième fois.
Constatations:
Afin de consolider toutes ces notions, raisonnons maintenant sur un cas un peu plus compliqué, metttant en scène le fichier lbjr:
et le fichier defvar
(Remarquons le caractère d'échappement "\" qui enlève au blanc qui suit le mot "Big" son rôle de séparateur)
Exécutons lbjr. Mais comme nous n'avons pas le courage de le rendre exécutable, procédons en utilisant la commande bash:
Analysons le résultat:
Nous n'avons pas eu le courage de rendre lbjr exécutable, mais bash c'est quand même très long à écrire: pourquoi ne pas utiliser sh?
Après tout sh est maintenant le plus souvent un simple lien vers bash:
Et pourtant:
Et oui : le comportement de bash change suivant la façon dont il est invoqué.
Le mieux est d'indiquer précisément l'endroit où se trouve le fichier à sourcer, ce qui évite ce genre d'erreur.
Pour en revenir avec le problème qui a motivé ce billet, la solution est bien évidemment de sourcer def-var dans le shell bash de travail. Les variables d'environnement, nouvelles où modifiées, seront ainsi présentes pour tous les processus fils
export QTDIR=`kde4-config --qt-prefix`
export KDEDIR=`kde4-config --prefix`
export KDEDIRS=$KDEDIR
export KDE_BUILD=$KDEDIR
export DBUSDIR=$KDEDIR
export LD_LIBRARY_PATH=$QTDIR/lib:$KDEDIR/lib:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=$DBUSDIR/lib/pkgconfig:/usr/lib/pkgconfig
export PATH=$QTDIR/bin:$KDEDIR/bin:$PATH
export KDEDIR=`kde4-config --prefix`
export KDEDIRS=$KDEDIR
export KDE_BUILD=$KDEDIR
export DBUSDIR=$KDEDIR
export LD_LIBRARY_PATH=$QTDIR/lib:$KDEDIR/lib:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=$DBUSDIR/lib/pkgconfig:/usr/lib/pkgconfig
export PATH=$QTDIR/bin:$KDEDIR/bin:$PATH
Si nous exécutons def-var dans un terminal et que nous regardons ensuite ce qu'il en est au niveau des variables d'environnement existant dans le terminal, rien n'est changé.
Alors comment procéder? Taper toutes ces commandes?
Non, bien sûr: il existe une autre méthode.
Bon, reprenons en partant d'un fichier un peu plus ludique: le fichier bjr:
echo $PPID-$$
echo Saisis un nom $moi
read moi
cat << FIN
Toujours saluer le directeur:
Bonjour $moi
FIN
echo Saisis un nom $moi
read moi
cat << FIN
Toujours saluer le directeur:
Bonjour $moi
FIN
situé dans /home/toto/test.
Ce fichier contient toute une série de commandes.
Elles sont là, déjà écrites dans le fichier! Alors pourquoi les retaper?
Il suffit d'indiquer à bash que bjr constitue une source de commandes:
L'output de la commande echo est affiché en premier. Puis la commande "read moi" provoque l'affichage du curseur: le système est en attente de ce que nous allons taper au clavier afin de le mettre dans la variable moi:
Terminons la saisie par un appui sur ENTER:
Tapons effectivement à l'écran la première commande de bjr:
Le résultat est le même: 2849 est le pid du shell bash dans lequel nous sommes et 2838 celui de son processus parent (par exemple konsole ou gnome-terminal)
Lorsque bjr est sourcé, tout se passe comme si les commandes qu'il contient étaient tapées à l'écran. Ainsi la variable moi est maintenant définie dans le shell bash (pid 2849) avec la valeur "Ahuri".
Le mot "source" étant très long (et donc fatiguant à taper), il est le plus souvent remplacé par un point ("."):
Nous constatons que la variable moi est bel et bien définie (elle contient le mot "Ahuri") avant même l'exécution de la commande read
Et si nous exécutions bjr en tapant tous simplement son nom, comme pour n'importe quelle commande?
Problème:
C'est normal, bjr n'est pas trouvé car /home/toto/test ne figure dans la variable d'environnement PATH qui contient l'ensemble des répertoires où le système recherche les commandes.
Par curiosité, examinons le contenu de PATH:
/home/toto/test n'y figure évidemment pas, mais bien à toutes fins utiles /home/toto/bin.
Ainsi nous pourrions créer le lien symbolique qui convient.
ln -s ../test/bjr ../bin
Mais la réponse classique au problème consiste à indiquer au système où se trouve exactement la commande à exécuter en tapant:/home/toto/test/bjr
ou plus court:./bjr
En fait c'est la même chose:
Nous affichons d'abord les inodes des différents fichiers du dossier (y compris les fichiers cachés). En faisant une recherche sur l'inode 1717900 nous voyons que le fichier "." n'est autre que le dossier dans lequel on se trouve (/home/toto/test).
Ceci est bien connu et a déjà été expliqué dans un autre billet.
Le point (.) peut donc être mangé à plusieurs sauces.
Résumons:
. bjr : le point remplace la commande "source". bjr sera sourcé.
./bjr : le point remplace (ici) /home/toto/test. bjr sera exécuté.
Procédons à l'exécution (!):
Nouveau problème! Et oui: personne n'a le droit d'exécuter ce fichier, même pas le root.
Avant de procéder il faut d'abord donner le droit d'exécution sur bjr (avec la commande chmod +x bjr):
Intéressons nous à ce que vaut maintenant la variable moi dans le shell bash de base:
C'est encore la valeur résultant du "read" lorsque bjr a été sourcé pour la deuxième fois.
Constatations:
- Les différentes commandes du script bjr, s'exécutent au sein d'un sous-shell (pid 2946) dérivé du shell bash principal (pid 2849).
- Dans ce sous-shell, la variable moi n'est au départ pas définie (elle prend ensuite la valeur Jules).
- L'exécution de bjr ne modifie pas la valeur de la variable moi dans le shell bash principal (contrairement à ce qui se passe lorsque bjr est sourcé).
- Elle aurait alors été définie d'emblée dans le sous-shell 2946 et la ligne 2 du résultat de l'exécution de bjr aurait été: Saisis un nom Patate
- Sa valeur serait comme avant restée inchangée au niveau shell maître
Afin de consolider toutes ces notions, raisonnons maintenant sur un cas un peu plus compliqué, metttant en scène le fichier lbjr:
echo $PPID-$$
echo Bonjour $moi
. defvar
./bjr
echo Il répondra: appelez-moi $moi
echo Bonjour $moi
. defvar
./bjr
echo Il répondra: appelez-moi $moi
et le fichier defvar
echo $PPID-$$
moi=Big\ Boss
moi=Big\ Boss
(Remarquons le caractère d'échappement "\" qui enlève au blanc qui suit le mot "Big" son rôle de séparateur)
Exécutons lbjr. Mais comme nous n'avons pas le courage de le rendre exécutable, procédons en utilisant la commande bash:
Analysons le résultat:
- ligne 1: lbjr s'exécute dans un sous-shell (pid 2949)
- ligne 2: dans ce sous-shell la variable moi n'est pas définie
- ligne 3: defvar est sourcé au niveau du sous-shell et la commande echo de defvar s'exécute bien dans ce sous-shell
- ligne 4: bjr s'exécute dans un sous-sous-shell (pid 2950)
- dernière ligne: bjr est terminé, on est retombé dans le sous-shell 2949 et la variable moi est est maintenant définie dans ce sous-shell car defvar y a été sourcé.
Nous n'avons pas eu le courage de rendre lbjr exécutable, mais bash c'est quand même très long à écrire: pourquoi ne pas utiliser sh?
Après tout sh est maintenant le plus souvent un simple lien vers bash:
Et pourtant:
Et oui : le comportement de bash change suivant la façon dont il est invoqué.
Le mieux est d'indiquer précisément l'endroit où se trouve le fichier à sourcer, ce qui évite ce genre d'erreur.
Pour en revenir avec le problème qui a motivé ce billet, la solution est bien évidemment de sourcer def-var dans le shell bash de travail. Les variables d'environnement, nouvelles où modifiées, seront ainsi présentes pour tous les processus fils
Post a Comment