Wie kann mein Skript feststellen, ob es von Bash oder Dash ausgeführt wird?

13

Ich führe eine neue Oneiric-Installation (dh kein Upgrade) auf zwei verschiedenen Systemen aus und stoße auf die gleichen scheinbar verwandten Probleme.

Am frustrierendsten ist, dass mich die Anmeldung bei X über LightDM sofort abmeldet, wenn ich die Dateien .profile und .bashrc verwende, die ich von Mac OS X mitgenommen habe. Ich glaube, das liegt an der Tatsache, dass es sich beim Ausführen von "/ bin / sh" wie / bin / dash verhält, aber die Variable $ SHELL immer noch auf / bin / bash gesetzt ist.

Hochrechnung

Ich habe eine riesige .bashrc. Sie können es hier sehen, wenn Sie möchten, aber der Inhalt ist wahrscheinlich nicht relevant, abgesehen von der Tatsache, dass es voller Bashismen ist und dass es in xterm oder auf einer virtuellen Konsole fehlerfrei funktioniert.

Mein .profilesieht so aus (abgekürzt):

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

Wenn ich versuche, mich über LightDM bei X anzumelden, werde ich sofort wieder abgemeldet. Ich bekomme Fehler in .xsession-errorsBezug auf meine .bashrc, die so aussehen (abgekürzt):

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

Wie gesagt, wenn ich Bash von einer virtuellen Konsole aus starte, werden diese Fehler nicht angezeigt. Wenn ich mein .profile entferne, kann ich mich außerdem problemlos bei X anmelden. (Ich kann mich auch bei einer virtuellen Konsole anmelden und startxdamit eine funktionierende X-Sitzung einleiten, aber dies ist natürlich keine langfristige Lösung.)

Allerdings habe ich festgestellt , dass , wenn ich laufe /bin/sh -l, ich kann die Fehler bekommen. Hier ist eine Beispielsitzung (Hinweis: Die Bash-Eingabeaufforderung, auf die ich vereinfacht habe bash>, und die Sh-Eingabeaufforderung sind nur $):

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

$

F1: Warum passiert das?

Ich verstehe, dass / bin / sh jetzt eher auf dash als auf bash verweist , aber wenn das wahr ist, warum $SHELLkehrt es dann immer noch zurück /bin/bash?

F2: Was kann ich tun, um das Problem zu umgehen?

Gibt es eine Möglichkeit, dies zu umgehen? Ich möchte, dass mein Profil .bashrc lädt, damit ich auf Anmelde- und Nicht-Anmelde-Shells die gleiche Umgebung erhalte, aber natürlich soll es nur für die Bash selbst geladen werden, nicht für / bin / sh, das sich als Bash tarnt.

Möglicherweise haben Sie den Unterschied im Inhalt der obigen Variablen $ BASH_VERSION bemerkt. Ich habe versucht, mein .profile in etwas einzuwickeln:

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

Der -nTest sollte nur dann true zurückgeben, wenn die Länge der Zeichenfolge nicht null ist, obwohl in der obigen Sitzung, wenn ich unter /bin/sh -ldieser ausgeführt werde, eine leere Zeichenfolge für $ BASH_VERSION zurückgegeben wird, wenn diese in meinem Profil wie folgt enthalten ist , es besteht den Test! Wenn sie fortfahren, meine .bashrc-Datei zu beziehen, geben Sie mir dieselben Fehler wie zuvor.

Jetzt bin ich wirklich verwirrt.

Micah R Ledbetter
quelle
Beachten Sie, dass dash -lauch $SHELLder Wert angezeigt wird /bin/bash.
Scott Severance
3
$SHELList, was das letzte Feld in /etc/passwd(oder getent passwd) sagt.
Bis auf weiteres angehalten.
@DennisWilliamson Danke , das musste ich wissen, um die richtige Antwort zu finden.
Micah R Ledbetter
Du machst es falsch. Sie sollten nicht-bash-spezifische Umgebungen ~/.profileund bash-spezifische Dinge einbinden ~/.bashrcund beide ~/.bash_profileQuellen haben .
nyuszika7h

Antworten:

12

Sie können die Tatsache, dass $BASH_VERSIONin der dashArbeit für Sie leer ist :

if [ "$BASH_VERSION" = '' ]; then
    echo "This is dash."
else
    echo "This is bash."
fi
Scott Severance
quelle
2
Die "x" -Technik ist archaisch und wird nur in alten Muscheln benötigt . Verwendungif [ "$BASH_VERSION" = '' ]
Bis auf weiteres angehalten.
@ TennisWilliamson: Danke. Ich hatte gedacht, dass Ihre Technik spezifisch für Bash ist, aber ich habe sie einfach in Dash ruhen lassen und es hat funktioniert. Ich habe meine Antwort bearbeitet.
Scott Severance
Oder einfach benutzen-n oder nichts . (+1, = ''funktioniert aber sehr gut.)
Eliah Kagan
5

Sie müssen lediglich Anführungszeichen für die BASH_VERSIONzu verwendende Variable verwenden-n

if [ -n "$BASH_VERSION" ];then
 echo "this is bash"; 
else 
 echo "this is dash";
fi
GM-Script-Writer-62850
quelle
1
da [ "$EMPTY_STRING" ]false ausgewertet wird, brauchst du das nicht mal -n. Sie müssen nur die Variable in Anführungszeichen setzen.
Jeberle
2

Verwenden Sie /proc/[PID]/cmdlinediese Option, um zu sehen, womit das Skript ausgeführt wird, und um zu testen, was es enthält. Die $$Variable gibt uns die PID der laufenden Shell. So können wir ein Skript wie dieses machen,

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

Hier ist ein Test desselben Skripts:

$> bash test_script.sh                                                                                                
This is bash
$> dash test_script.sh                                                                                                
This is some other shell
Sergiy Kolodyazhnyy
quelle
Dies funktioniert nicht auf einem Mac. Überprüfen Sie $ BASH_VERSION.
Austin Burk
2
@AustinBurk es muss nicht auf dem Mac funktionieren. Das ist Ask Ubuntu.
TheWanderer
@ Zacharee1 oh verdammt, ich habe nicht aufgepasst:)
Austin Burk
Ich möchte dies nicht so ändern, wie Sie es beabsichtigen, aber ich schlage vor, die Einschränkungen dieser Methode zu erwähnen. Bash muss nicht bashin seinem Namen haben; Es ist nicht ungewöhnlich, dass die bashausführbare Datei über einen Symlink mit einem anderen Namen ausgeführt wird. Normalerweise würde man diesen Bash immer noch in Betracht ziehen wollen. Außerdem wird das Muster an einer beliebigen Stelle in abgeglichen/proc/$$/cmdline , was korrigiert werden sollte. Beachten Sie jedoch, dass Argumente in durch cmdlineNullzeichen getrennt sind. grep -qE '(^|/)bash$'fühlt sich an wie es funktionieren sollte, gibt aber ein falsches positives wenn irgendein Argument ist bash.
Eliah Kagan
@EliahKagan Sie können meine Antworten jederzeit bearbeiten - Sie verfügen über ausreichende Fachkenntnisse, sodass ich weiß, dass Ihre Änderungen nur Verbesserungen bieten können. Die Antwort wurde geschrieben, als ich mit Muscheln viel grüner war als jetzt.
Sergiy Kolodyazhnyy