Comment mon script peut-il déterminer s'il est exécuté par bash ou dash?


13

J'exécute une nouvelle installation Oneiric (c'est-à-dire pas une mise à niveau) sur deux systèmes différents et rencontre le même ensemble de problèmes apparemment liés.

Le plus frustrant du groupe est que, lorsque j'utilise le .profile et .bashrc que j'ai emporté avec moi depuis Mac OS X, la connexion à X via LightDM me déconnecte immédiatement. Je crois que cela est dû au fait que, lors de l'exécution de "/ bin / sh", il se comporte comme / bin / dash, mais a toujours la variable $ SHELL définie sur / bin / bash.

Extrapolation

J'en ai un énorme .bashrc. Vous pouvez le voir ici si vous le souhaitez, mais son contenu n'est probablement pas pertinent, à part le fait qu'il est plein de bashismes et le fait qu'il fonctionne sans erreur à l'intérieur de xterm ou sur une console virtuelle.

Mon .profileressemble à ceci (abrégé):

case $SHELL in 
*bash*)
    if [ -f $HOME/.bashrc -a -r $HOME/.bashrc ]; then
        . $HOME/.bashrc
    fi
    ;;
esac

Si j'essaie de me connecter à X via LightDM, cela me déconnectera immédiatement. Je reçois des erreurs .xsession-errorsconcernant mon .bashrc qui ressemblent à ceci (en abrégé):

/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found

Comme je l'ai dit, lorsque j'exécute bash à partir d'une console virtuelle, je n'obtiens pas ces erreurs. De plus, si je supprime mon .profile, je peux très bien me connecter à X. (Je peux également me connecter à une console virtuelle et l'utiliser startxpour lancer une session X qui fonctionne, mais ce n'est bien sûr pas une solution à long terme.)

Cependant, j'ai découvert que si je cours /bin/sh -l, je ne reçois les erreurs. Voici un exemple de session (remarque: l'invite bash que j'ai simplifiée bash>et l'invite sh est juste $):

bash> echo $SHELL
/bin/bash
bash> echo $BASH_VERSION
4.2.10(1)-release
bash> /bin/sh -l
/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found
$ echo $SHELL
/bin/bash
$ echo $BASH_VERSION

$

Q1: Pourquoi cela se produit-il?

Je comprends que / bin / sh pointe maintenant vers un tiret plutôt que vers bash , mais si c'est vrai, alors pourquoi revient-il $SHELLencore /bin/bash?

Q2: Que puis-je faire pour contourner ce problème?

Y a-t-il un moyen de contourner cela? Je veux garder mon profil en charge .bashrc afin que j'obtienne le même environnement sur les shells de connexion et non-login, mais évidemment je veux seulement qu'il se charge pour bash lui-même, pas / bin / sh se faisant passer pour bash.

Vous avez peut-être remarqué la différence dans le contenu des variables $ BASH_VERSION ci-dessus. J'ai essayé d'envelopper mon .profile dans quelque chose comme ceci:

if [ -n $BASH_VERSION ]; then
    # the rest of my .profile as above
fi

Le -ntest ne doit renvoyer true que si la longueur de la chaîne n'est pas nulle, cependant, même si dans la session ci-dessus, lorsque je cours sous, /bin/sh -lil retourne une chaîne vide pour $ BASH_VERSION, lorsqu'elle est incluse dans mon .profile comme ceci , ça passe le test! Il les procède à la source de mon .bashrc et me donne les mêmes erreurs qu'auparavant.

Maintenant, je suis vraiment confus.


Notez que dash -lmontre également $SHELLavoir la valeur /bin/bash.
Scott Severance

3
$SHELLest tout ce que le dernier champ de /etc/passwd(ou getent passwd) dit.
pause jusqu'à nouvel ordre.

@DennisWilliamson Merci , c'est ce que je devais savoir pour trouver la bonne réponse.
Micah R Ledbetter du

Vous le faites mal. Vous devez placer un environnement non spécifique à ~/.profilebash, des choses spécifiques à bash ~/.bashrcet avoir la ~/.bash_profilesource à la fois.
nyuszika7h

Réponses:


12

Vous pouvez faire en sorte que le fait qui $BASH_VERSIONsoit vierge dashvous corresponde:

if [ "$BASH_VERSION" = '' ]; then
    echo "This is dash."
else
    echo "This is bash."
fi

2
La technique du «x» est archaïque et n'est nécessaire que dans les coquilles anciennes . Utilisationif [ "$BASH_VERSION" = '' ]
pause jusqu'à nouvel ordre.

@DennisWilliamson: Merci. J'avais pensé que votre technique était spécifique à Bash, mais je l'ai simplement reposée dans Dash et cela a fonctionné. J'ai édité ma réponse.
Scott Severance

Ou utilisez-n simplement , ou rien . (+1, cependant. = ''Fonctionne parfaitement bien.)
Eliah Kagan

5

Il vous suffit d'utiliser des guillemets sur la variable BASH_VERSIONà utiliser-n

if [ -n "$BASH_VERSION" ];then
 echo "this is bash"; 
else 
 echo "this is dash";
fi

1
puisque [ "$EMPTY_STRING" ]évalue faux, vous n'avez même pas besoin de -n. Il suffit de citer la variable.
jeberle

2

Utilisez /proc/[PID]/cmdlinepour voir avec quoi le script est exécuté et tester ce qu'il contient. La $$variable nous donnera le PID du shell en cours d'exécution. Ainsi, nous pouvons faire un script comme celui-ci,

#!/bin/bash
if grep -q 'bash' /proc/$$/cmdline ;
then
    echo "This is bash"
else
    echo "This is some other shell"
fi

Voici un test du même script:

$> bash test_script.sh                                                                                                
This is bash
$> dash test_script.sh                                                                                                
This is some other shell

Cela ne fonctionnera pas sur Mac. Vérifiez $ BASH_VERSION.
Austin Burk

2
@AustinBurk, il n'a pas besoin de fonctionner sur Mac. C'est Ask Ubuntu.
TheWanderer

@ Zacharee1 oh sacrément, je ne faisais pas attention
Austin Burk

Je ne veux pas modifier cela loin de ce que vous avez l'intention, mais je suggère de mentionner les limites de cette méthode. Bash n'a pas besoin d'avoir bashson nom; il n'est pas rare que l' bashexécutable soit exécuté via un lien symbolique avec un autre nom. Habituellement, on voudrait toujours considérer ce Bash. En outre, le modèle est mis en correspondance n'importe où dans/proc/$$/cmdline , ce qui devrait être possible de corriger, mais gardez à l'esprit que les arguments cmdlinesont délimités par des caractères nuls. grep -qE '(^|/)bash$'se sent comme si cela devrait fonctionner mais donne un faux positif quand un argument est bash.
Eliah Kagan

@EliahKagan N'hésitez pas à modifier mes réponses à tout moment - vous avez une expertise suffisante pour que je sache que vos modifications ne peuvent offrir que des améliorations. La réponse a été écrite quand j'étais beaucoup plus verte avec des coquillages que je ne le suis maintenant.
Sergiy Kolodyazhnyy
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.