W jaki sposób mój skrypt może ustalić, czy jest uruchamiany przez bash czy myślnik?

13

Korzystam z nowej instalacji Oneiric (tj. Bez aktualizacji) na dwóch różnych systemach i napotykam ten sam zestaw pozornie powiązanych problemów.

Najbardziej frustrujące jest to, że kiedy używam .profile i .bashrc, które zabrałem ze sobą z Mac OS X, zalogowanie się do X przez LightDM natychmiast mnie wylogowuje. Sądzę, że jest to spowodowane faktem, że po uruchomieniu „/ bin / sh” zachowuje się jak / bin / dash, ale nadal ma zmienną $ SHELL ustawioną na / bin / bash.

Ekstrapolacja

Mam ogromny .bashrc. Możesz go zobaczyć tutaj, jeśli chcesz, ale jego zawartość prawdopodobnie nie jest istotna, poza tym, że jest pełen bashism i faktu, że działa bez błędów w xterm lub na wirtualnej konsoli.

Kim .profilewygląda następująco (w skrócie):

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

Jeśli spróbuję zalogować się do X przez LightDM, natychmiast mnie wyloguje. Występują błędy .xsession-errorszwiązane z moim .bashrc, które wyglądają tak (w skrócie):

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

Jak powiedziałem, kiedy uruchamiam bash z wirtualnej konsoli, nie otrzymuję tych błędów. Ponadto, jeśli usunę mój .profile, mogę zalogować się do X w porządku. (Mogę również zalogować się do wirtualnej konsoli i użyć startxdo zainicjowania sesji X, która działa, ale nie jest to oczywiście rozwiązanie długoterminowe).

Jednak odkryłem, że jeśli biegnę /bin/sh -l, ja nie dostać błędy. Oto przykładowa sesja (uwaga: podpowiedź bash, którą uprościłem bash>, a podpowiedź sh jest tylko $):

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

$

P1: Dlaczego tak się dzieje?

Rozumiem, że / bin / sh wskazuje teraz na myślnik zamiast na bash , ale jeśli to prawda, to dlaczego $SHELLwciąż powraca /bin/bash?

Q2: Co mogę zrobić, aby obejść ten problem?

Czy istnieje sposób na obejście tego? Chcę, aby mój profil ładował plik .bashrc, aby uzyskać to samo środowisko zarówno dla powłok logowania, jak i bez logowania, ale oczywiście chcę, aby ładowało się tylko dla samego basha, a nie / bin / sh podszywającego się pod bash.

Być może zauważyłeś różnicę w treści zmiennych $ BASH_VERSION powyżej. Próbowałem zawinąć mój .profile w coś takiego:

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

-nTest powinien wrócić prawdziwe tylko wtedy, gdy długość łańcucha jest różna od zera, jednak, choć w sesji powyżej, kiedy biegnę pod /bin/sh -lzwraca pusty ciąg dla $ BASH_VERSION, gdy jest zawarte w moim .profile jak ta , przechodzi test! Następnie przechodzą do źródła .bashrc i dają te same błędy, co poprzednio.

Teraz jestem naprawdę zdezorientowany.

Micah R. Ledbetter
źródło
Zauważ, że dash -lpokazuje również $SHELLposiadanie wartości /bin/bash.
Scott Severance
3
$SHELLjest tym, co mówi ostatnie pole w /etc/passwd(lub getent passwd).
Wstrzymano do odwołania.
@DennisWilliamson Dziękuję , właśnie to musiałem wiedzieć, aby znaleźć właściwą odpowiedź.
Micah R Ledbetter
Robisz to źle. Powinieneś umieścić środowisko niespecyficzne dla ~/.profilebash, rzeczy specyficzne dla bash ~/.bashrci mieć ~/.bash_profileoba źródła.
nyuszika7h

Odpowiedzi:

12

Możesz sprawić, że fakt, który $BASH_VERSIONjest pusty, dashdziała dla Ciebie:

if [ "$BASH_VERSION" = '' ]; then
    echo "This is dash."
else
    echo "This is bash."
fi
Scott Severance
źródło
2
Technika „x” jest archaiczna i potrzebna tylko w starożytnych muszlach. Użyjif [ "$BASH_VERSION" = '' ]
wstrzymano do odwołania.
@DennisWilliamson: Dzięki. Myślałem, że twoja technika jest specyficzna dla Basha, ale po prostu odpoczywałem w Dash i zadziałało. Zredagowałem swoją odpowiedź.
Scott Severance
Lub po prostu użyj-n lub nic . (+1, chociaż. = ''Działa doskonale.)
Eliah Kagan
5

Wystarczy użyć cudzysłowu na zmiennej, BASH_VERSIONaby użyć-n

if [ -n "$BASH_VERSION" ];then
 echo "this is bash"; 
else 
 echo "this is dash";
fi
GM-Script-Writer-62850
źródło
1
ponieważ [ "$EMPTY_STRING" ]ocenia fałsz, nawet nie potrzebujesz -n. Musisz tylko podać zmienną.
jeberle,
2

Użyj, /proc/[PID]/cmdlineaby zobaczyć, z czym skrypt jest uruchamiany i przetestować, co zawiera. $$Zmienna da nam PID uruchomionego powłoki. W ten sposób możemy stworzyć taki skrypt,

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

Oto test tego samego skryptu:

$> bash test_script.sh                                                                                                
This is bash
$> dash test_script.sh                                                                                                
This is some other shell
Sergiy Kolodyazhnyy
źródło
To nie będzie działać na Macu. Sprawdź $ BASH_VERSION.
Austin Burk
2
@AustinBurk nie musi działać na komputerze Mac. To jest Ask Ubuntu.
TheWanderer
@ Zacharee1 o rany, nie zwracałem uwagi:,)
Austin Burk
Nie chcę edytować tego z dala od tego, co zamierzasz, ale sugeruję wspomnienie o ograniczeniach tej metody. Bash nie musi mieć bashw swoim imieniu; zdarza się, że bashplik wykonywalny jest uruchamiany przez dowiązanie symboliczne o innej nazwie. Zwykle nadal chciałoby się rozważyć Bash. Ponadto wzorzec jest dopasowywany w dowolnym miejscu/proc/$$/cmdline , co powinno być możliwe do naprawienia, ale należy pamiętać, że argumenty cmdlinesą rozdzielane znakami zerowymi. grep -qE '(^|/)bash$'wydaje się, że powinno działać, ale daje fałszywy wynik pozytywny, gdy jest jakiś argument bash.
Eliah Kagan
@EliahKagan Zapraszam do edycji moich odpowiedzi w dowolnym momencie - masz wystarczającą wiedzę specjalistyczną, więc wiem, że Twoje zmiany mogą oferować tylko ulepszenia. Odpowiedź została napisana, gdy byłem znacznie bardziej zielony z muszlami niż teraz.
Sergiy Kolodyazhnyy