спосіб визначення поточної оболонки, сумісний з контрольними башизмами


18

В моєму випадку .profileя використовую такий код, щоб переконатися, що псевдоніми та функції, пов'язані з Bash, розміщуються лише у тому випадку, якщо оболонкою входу фактично є Bash :

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

Наразі я перебуваю під керуванням версій файлів конфігурації оболонок, сценаріїв та функцій. Нещодавно я також розпочав процес видалення випадкових башизмів із скриптів оболонки, які не користуються особливостями Bash, наприклад, заміною function funcname()на funcname().

Для мого сховища файлів оболонки я налаштував гачок, що попередньо здійснює запуск, який запускає checkbashismsутиліту з пакета devscripts Debian для кожного shфайлу в сховищі, щоб переконатися, що я ненавмисно не ввожу специфічний для синтаксису Bash синтаксис. Однак це спричиняє помилку для мого .profile:

possible bashism in .profile line 51 ($BASH_SOMETHING):
if [ "${BASH_VERSION:-}" ]; then

Мені було цікаво, чи існує спосіб перевірити, яка оболонка працює, що не призведе до попередження checkbashisms.

Я перевірив список змінних оболонок, перелічених POSIX, сподіваючись, що одна з них може використовуватись для показу поточної оболонки. Я також переглянув змінні, встановлені в інтерактивній оболонці Dash, але, знову ж таки, не вдалося знайти відповідного кандидата.

На даний момент я виключив .profileобробку checkbashisms; це невеликий файл, тому перевірити його вручну не важко. Однак, вивчивши проблему, я все-таки хотів би знати, чи існує метод, сумісний з POSIX, щоб визначити, яка оболонка запущена (або принаймні спосіб, який не спричиняє checkbashismsзбій).


Подальша довідка / уточнення

Однією з причин, за допомогою яких я конфігурую свої файли конфігурації оболонки під управлінням версій, - це налаштувати моє середовище на всіх системах, в які я регулярно входжу в систему: Cygwin, Ubuntu та CentOS (і 5, і 7, використовуючи Active Directory для користувача аутентифікація). Я найчастіше входжу через X Windows / настільні середовища та SSH для віддалених хостів. Однак я хотів би, щоб це було в майбутньому і мав найменшу залежність від системних залежностей та інших можливих інструментів.

Я використовую checkbashismsяк просту автоматизовану перевірку правильності для синтаксису моїх файлів, пов’язаних із оболонкою. Це не ідеальний інструмент, наприклад, я вже застосував патч до нього, щоб він не скаржився на використання command -vв моїх сценаріях. Під час дослідження я дізнався, що фактична мета програми - забезпечити відповідність політиці Debian, яка, наскільки я розумію, базується на POSIX 2004, а не 2008 (або її перегляд 2013 року).


Те, що ви робите, так само сумісне з POSIX, як і щось, коли вся справа в тому, щоб працювати в різних середовищах, сумісних з POSIX. Ваша яловичина з чекбашизмами.
Жил "ТАК - перестань бути злим"

І до речі, я ніколи не використовував чекбашизми, щоб перевірити переносимість своєї конфігурації. Я перевіряю це, використовуючи його в різних системах.
Жил "ТАК - перестань бути злим"

2
І до речі, для конкретної речі, яку ви тут робите, пишіть .bash_profileджерела, що є джерелами, .profileі (умовно) .bashrc.
Жил "ТАК - перестань бути злим"

Дякуємо за відгук @Gilles. Це дуже елегантне рішення конкретного питання.
Ентоні Г - справедливість для Моніки

Відповіді:


16

Ваша

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

код повністю відповідає POSIX і найкращий спосіб перевірити, чи ви працюєте в даний час bash. Звичайно, $BASH_VERSIONзмінна є специфічною для bash, але саме для цього ви її використовуєте! Щоб перевірити, чи ти працюєш bash!

Зверніть увагу, що $BASH_VERSIONбуде встановлено, bashбуде викликано як bashабо sh. Після того, як ви підтвердили, що ви працюєте bash, ви можете використовувати [ -o posix ]в якості індикатора, що оболонку викликали як sh(хоча ця опція також встановлюється, коли POSIXLY_CORRECT знаходиться в оточенні або bashвикликається з -o posix, або з SHELLOPTS = posix в оточенні. Але у всіх тих випадках bashбуде вести себе так, ніби називається так sh).


Ще одна змінна, яку ви можете використовувати замість неї, $BASH_VERSIONі на яку checkbashism, схоже, не скаржитеся, якщо не буде передана -xопція $BASH. Це також властиво bashтому, що ви також повинні мати можливість визначати, бігаєте ви bashчи ні.


Я також зауважу, що це насправді не належне використання checkbashisms. checkbashismsце інструмент, який допоможе вам писати портативні shсценарії (відповідно до shспецифікацій у політиці Debian, набір POSIX), він допомагає виявити нестандартний синтаксис, який запроваджують люди, що пишуть сценарії в системах, на які shє симпосилання bash.

A .profileінтерпретується різними оболонками, багато з яких не відповідають стандартам POSIX. Як правило, ви не використовуєте в shякості реєстраційної оболонки, але шкаралупа подобається zsh, fishабо bashз більш розширеними інтерактивними можливостями.

bashі zsh, коли вони не викликаються як shі коли відповідний файл сеансу профілю ( .bash_profile, .zprofile) не відповідає POSIX (особливо zsh), але все ще читається .profile.

Отже, це не синтаксис POSIX, який ви хочете, .profileа синтаксис, сумісний з POSIX (для sh), bashі zshякщо ви коли-небудь використовувати ці оболонки (можливо, навіть Bourne як оболонка Bourne також читається, .profileале зазвичай не зустрічається в системах на базі Linux ).

checkbashismsОднозначно допоможе вам з’ясувати башизми, але може не вказати на синтаксис POSIX, який не сумісний з zshабо bash.

Тут, якщо ви хочете використовувати bashспецифічний код (як, наприклад, обхід цієї bashпомилки, згідно з якою вона не читається ~/.bashrcв інтерактивних оболонках входу), кращим підходом було б це ~/.bash_profileзробити (до або після пошуку, ~/.profileде ви розміщуєте ваш загальний сеанс ініціалізації).


Це не проходить checkbashismsчерез використану змінну.
Томас Дікі

2
@ThomasDickey, так, але це випадок, коли звіт про перевірку басизмів слід ігнорувати. Усі інші рішення, що даються до цього часу, значно гірші.
Стефан Шазелас

@ StéphaneChazelas Ви говорите, що всі інші рішення гірші. Що було б неправильним у використанні $0для цього конкретного випадку?
Ентоні Г - справедливість для Моніки

2
@AnthonyGeoghegan Це не розрізняє bash, що називається як, shі іншу оболонку, яку називають як sh.
Жил "ТАК - перестань бути злим"

Це також дає хибний позитив, якщо dashабо інша не-баш оболонка була неправильно викликана з argv[0] == "bash", що цілком законно, якщо малоймовірно.
Кевін

17

Зазвичай $0для цього використовується. На сайті, з яким ви пов’язали його, стоїть:

0
   (Zero.) Expands to the name of the shell or shell script.

Так просто! Я настільки звик використовувати $0для назви скрипту оболонки, що я чисто забув, що він також може стосуватися поточної оболонки. Спасибі!
Ентоні Г - справедливість для Моніки

1
Як зазвичай, цю конвенцію дотримуються всі добре сприйняті програми, але шкідлива програма може зіпсуватись з вами, використовуючи різні системні дзвінки з execсім’ї, оскільки вони дозволяють програмі, що викликає, ідентифікувати бінарний запуск окремо від рядка, який передається як аргумент 0.
dmckee

Це працює для .profile :) мило
Роб

5

Зазвичай змінна середовища SHELL повідомляє вам оболонку за замовчуванням. Вам не потрібно вручну подавати джерело .bashrc-файлу (неправда див. Нижче оновлення), bash повинен зробити це автоматично, просто переконайтеся, що він знаходиться в каталозі $ HOME.

Інший варіант - зробити щось на кшталт:

 ps -o cmd= $$

яка скаже вам команду (без аргументів значення = без значення не відображатиме заголовки стовпців) поточного процесу. Приклад виводу:

 $ps -o cmd= $$
 bash
 $sh
 $ps -o cmd= $$
 sh

ОНОВЛЕННЯ:

Я стою виправлений! :)

.Bashrc не завжди використовується, як згадувалося в коментарях нижче та /programming/415403/whats-the-difference-between-bashrc-bash-profile-and-environment

Таким чином, ви можете перемістити свій .bashrc до .bash_profile і побачити, чи це працює, не тестуючи. Якщо ні, ви не маєте тесту вище.


1
.bashrcнасправді не використовується оболонкою для входу, але .profile(якщо вона існує) або .bash_profileє. SHELLне визначено POSIX і, на жаль, не є cmdопцією форматування для ps.
Ентоні Г - справедливість для Моніки

1
Це я б використовував, але це також піддається зловмисним маніпуляціям.
dmckee

Зауважте, що хоча ця ps -o cmd= $$робота повинна працювати майже скрізь, $SHELLзмінна абсолютно не має значення. Це оболонка користувача за замовчуванням і не має ніякого відношення до того, яка оболонка запущена в даний момент або яка сценарій оболонки працює.
тердон

2
Не дуже, ні. багато оболонок будуть прочитані, ~/.profileколи їх запустять як оболонки для входу. Так, наприклад, ваш $SHELLміг бути cshі ви біжите bash -l. Це почне bash як оболонку входу, тому воно буде читатися ~/.profile, але $SHELLвсе одно вкажете на csh. Плюс .profileможе бути, явно поставлений інший сценарій. Оскільки ОП збирається досягти максимальної стійкості, слід враховувати всілякі випадки. У будь-якому випадку $SHELLне надає корисної інформації про поточно працюючу оболонку.
тердон

2
FWIW, я теж виправлений - про SHELLте, що POSIX не визначається: pubs.opengroup.org/onlinepubs/9699919799/basedefs/…
Ентоні Г - справедливість для Моніки

4

Питання задає оболонку для входу користувача, а також поточну оболонку у такий спосіб, який сподобається checkbashisms. Якщо це мається на увазі оболонка, на якій користувач увійшов, я б використав цей /etc/passwd, наприклад,

MY_UID=$(id -u)
MYSHELL=$(awk -F: '$3 == '$MY_UID'{ print $7; }' </etc/passwd )

Звичайно, користувачі можуть запустити нову оболонку після входу в систему. Звичайно, якщо один є bash, а другий - ні, тести змінних середовища bash можуть не допомогти.

Деякі можуть скористатися файлом, getentа не просто passwdфайлом (але це не стосується питання).

На основі коментаря про LDAP та пропозиції щодо lognameцієї альтернативної форми можна використовувати:

MY_NAME=$(logname)
MYSHELL=$(getent passwd | awk -F: '$1 ~ /^'$MY_NAME'$/ {print $7;}' )

Під час тестування я помітив, що lognameне подобається, що його вхід перенаправлений (тому я залишив вираз розбитим). Швидкий показ перевірок getentповинен працювати на згаданих платформах (хоча це повинно бути передбачено в оригінальному запитанні):


1
Якщо припустити, що база даних користувачів знаходиться в / etc / passwd (не LDAP / NIS / mysql ...) і що на користувача є лише одне ім'я користувача. (краще було б перевірити перший стовпець проти $(logname)).
Стефан Шазелас

iirc, POSIX не визначає необхідну утиліту (або я б використав її у своїй відповіді). Використовувати idабо змінювати користувачем змінну - це інший вибір.
Томас Дікі

1
Зауважте, що я сказав $(logname), ні $LOGNAME. Ідентифікатор користувача, і оболонка входу отримуються з імені користувача, використовуваного при вході. Ви не можете повернутися з ідентифікатора користувача до оболонки входу, за винятком систем, де на ідентифікатор користувача є лише одне ім’я користувача. Або IOW, первинним ключем у базі даних користувачів є ім’я користувача, а не uid.
Стефан Шазелас

Дякуємо @ThomasDickey за відповідь з іншої точки зору. Однак це трохи складніше, ніж я думав (більше схожий на відповіді Джиммія та Стефана ). Однією з причин, за допомогою яких я можу конфігураційні файли оболонки під управлінням версій, - це налаштувати моє середовище на всіх системах, в які я регулярно входжу в систему: Cygwin, Ubuntu та CentOS (і 5, і 7, використовуючи Active Directory для користувача аутентифікація). З цієї причини я вважаю за краще зберігати логіку максимально просто.
Ентоні Г - справедливість для Моніки
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.