Як мій сценарій може визначити, керується він bash чи dash?


13

Я запускаю свіжу установку Oneiric (тобто не оновлення) на дві різні системи і стикаюся з тим самим набором, здавалося б, пов'язаних проблем.

Найбільш засмучує купу, що коли я використовую .profile та .bashrc, які я переніс із собою з Mac OS X, вхід у систему X через LightDM вимикає мене негайно. Я вважаю, що це викликано тим, що під час запуску "/ bin / sh" він поводиться як / bin / dash, але все ще має змінну $ SHELL, встановлену на / bin / bash.

Екстраполяція

У мене величезна .bashrc. Ви можете бачити його тут, якщо хочете, але його вміст, мабуть, не має значення, окрім того, що він повний башизмів, і того, що він працює без помилок усередині xterm або на віртуальній консолі.

Моє .profileвиглядає так (скорочено):

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

Якщо я спробую увійти до X через LightDM, він негайно вийдуть із мене назад. У мене виникають помилки .xsession-errorsстосовно мого .bashrc, які виглядають так (скорочено):

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

Як я вже говорив, коли я запускаю bash з віртуальної консолі, я не отримую цих помилок. Крім того, якщо я видалю .profile, я можу ввійти до X просто чудово. (Я також можу увійти у віртуальну консоль і використовувати startxдля ініціювання X-сеансу, який працює, але це, звичайно, не довгострокове рішення.)

Тим НЕ менше, я виявив , що якщо я біжу /bin/sh -l, я б отримати помилки. Ось приклад сеансу (зверніть увагу: підказку bash, яку я спростив bash>, і підказка sh просто $):

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: Чому це відбувається?

Я розумію, що / bin / sh тепер вказує на дефіс, а не баш , але якщо це правда, то чому все- $SHELLтаки повертається /bin/bash?

Q2: Що я можу зробити, щоб обійти його?

Чи є спосіб обійти це? Я хочу, щоб мій профіль завантажувався .bashrc, щоб я отримував однакове середовище як оболонок для входу, так і не вхідних даних, але очевидно, що я хочу лише завантажувати себе на bash, а не / bin / sh маскуватися під bash.

Можливо, ви помітили різницю у вмісті змінних $ BASH_VERSION вище. Я спробував завернути свій .profile у щось подібне:

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

-nТест повинен повертати вірно , тільки якщо довжина рядка не дорівнює нулю, однак, незважаючи на те, на сесії вище, коли я біжу під /bin/sh -lце повертає порожній рядок $ BASH_VERSION, коли він включений в моєму .profile , як це , проходить тест! Він переходить до джерела мого .bashrc і дає мені ті самі помилки, що і раніше.

Зараз я справді розгублений.


Зверніть увагу, що dash -lтакож показано, що $SHELLмає значення /bin/bash.
Скотт Северанс

3
$SHELLвсе, що сказано в останньому полі /etc/passwd(або getent passwd).
Призупинено до подальшого повідомлення.

@DennisWilliamson Дякую , саме це мені потрібно було знати, щоб знайти правильну відповідь.
Micah R Ledbetter

Ви робите це неправильно. Ви повинні помістити не-баш-середовище в ~/.profile, специфічні для bash речі ~/.bashrc, і мати ~/.bash_profileджерело обох.
nyuszika7h

Відповіді:


12

Ви можете зробити той факт, який $BASH_VERSIONпорожній у dashроботі для вас:

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

2
Техніка "х" є архаїчною і потрібна лише в древніх снарядах. Використанняif [ "$BASH_VERSION" = '' ]
призупинено до подальшого повідомлення.

@DennisWilliamson: Дякую Я думав, що ваша техніка є специфічною для Баша, але я просто відпочив її в Dash, і вона спрацювала. Я відредагував свою відповідь.
Скотт Северанс

Або просто використовувати-n , або нічого . (+1, однак. = ''Працює чудово.)
Елія Каган

5

Вам просто потрібно використовувати лапки на змінній, яку BASH_VERSIONпотрібно використовувати-n

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

1
оскільки [ "$EMPTY_STRING" ]оцінює помилкове, вам навіть це не потрібно -n. Вам просто потрібно процитувати змінну.
jeberle

2

Використовуйте, /proc/[PID]/cmdlineщоб побачити, з чим виконується сценарій, і перевірити, що він містить. $$Змінний дасть нам PID запущеної оболонки. Таким чином, ми можемо зробити такий сценарій,

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

Ось тест того ж сценарію:

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

Це не працюватиме на Mac. Перевірте $ BASH_VERSION.
Остін Берк

2
@AustinBurk йому не потрібно працювати на Mac. Це Ask Ubuntu.
TheWanderer

@ Zacharee1 ой, чорт, я не звертав уваги:,)
Остін Берк

Я не хочу редагувати це далеко від того, що ви маєте намір, але пропоную згадати обмеження цього методу. Баш не повинен мати bashсвоє ім'я; не рідкість, щоб bashвиконуваний файл був запущений через симпосилання з іншим іменем. Зазвичай все-таки хочеться розглянути цього Баша. Крім того , картина відповідає де - небудь в/proc/$$/cmdline , що повинно бути можливо виправити, але майте на увазі , що аргументи на cmdlineнуль-символ розмежовані. grep -qE '(^|/)bash$'вважає, що це має спрацювати, але дає хибний позитив, коли є будь-який аргумент bash.
Елія Каган

@EliahKagan Ви можете будь-коли редагувати мої відповіді - у вас достатньо досвіду, тому я знаю, що ваші зміни можуть запропонувати лише вдосконалення. Відповідь була написана, коли я був набагато зеленіший від снарядів, ніж зараз.
Сергій Колодяжний
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.