HOWTO: обнаружение bash из сценария оболочки - PullRequest
8 голосов
/ 08 июля 2010

Сценарий таков, что пользователям предлагается ввести файл сценария:

$ source envsetup.sh

Этот файл скрипта может использовать только функцию bash, поэтому мы обнаружили, что запущенная оболочка является bash или нет.

Для других оболочек, имеющих общий синтаксис с bash, например, sh, zsh, ksh, я хотел бы сообщить предупреждение.

Какой самый надежный способ обнаружения текущей оболочки в Linux, Cygwin, OS X?

То, что я знаю, это $ BASH, но мне интересно, шансы, что оно может потерпеть неудачу.

Ответы [ 6 ]

13 голосов
/ 08 июля 2010

Существует множество переменных окружения, которые вы можете посмотреть, но многие из них не обнаружат, если из bash возникла другая оболочка.Рассмотрим следующее:

bash$ echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt"
SHELL: /bin/bash, shell: , ARGV[0]: -bash, PS1: bash$ , prompt: 

bash$ csh
[lorien:~] daveshawley% echo "SHELL: $SHELL, shell: $shell, \$0: $0, PS1: $PS1, prompt: $prompt"
SHELL: /bin/bash, shell: /bin/tcsh, ARGV[0]: csh, PS1: bash$ , prompt: [%m:%c3] %n%#

[lorien:~] daveshawley% bash -r
bash$ echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt"
SHELL: /bin/bash, shell: , ARGV[0]: sh, PS1: bash$ , prompt:

bash$ zsh
% echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt"
SHELL: /bin/bash, shell: , ARGV[0]: zsh, PS1: % , prompt: % 

% ksh
$ echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt"
SHELL: /bin/bash, shell: , ARGV[0]: ksh, PS1: bash$ , prompt: 

Существует целый ряд переменных, специфичных для различных оболочек, за исключением того, что они имеют привычку наследоваться вложенными оболочками, и именно в этом случае среда действительно нарушается.Единственное, что почти работает, это ps -o command -p $$.Технически это дает вам имя команды, под которой работает оболочка.В большинстве случаев это будет работать ... поскольку приложения запускаются с каким-либо вариантом системного вызова exec, и это позволяет различать имя команды и исполняемого файла, возможно, что это также может дать сбой.Подумайте:

bash$ exec -a "-csh" bash
bash$ echo "$0, $SHELL, $BASH"
-csh, /bin/bash, /bin/bash
bash$ ps -o command -p $$
COMMAND
-csh
bash$

Еще один прием - использовать lsof -p $$ | awk '(NR==2) {print $1}'.Вероятно, это настолько близко, насколько это возможно, если вам повезло иметь под рукой lsof.

10 голосов
/ 08 июля 2010

Это работает также

[ -z "$BASH_VERSION" ] && return
8 голосов
/ 11 декабря 2016

Вот хороший способ:

if test -z "$(type -p)" ; then echo bash ; else echo sh ; fi

, и вы, конечно, можете заменить операторы "echo" на что угодно.

=================

Обсуждение:

  • Переменная $SHELL указывает предпочитаемую пользователем оболочку ... которая ничего не говорит о запущенной оболочкев данный момент.

  • Тестирование $BASH_VERSION хорошая идея на 99%, но она может потерпеть неудачу, если какой-нибудь мудрец вставит переменную с таким именем в окружение sh.Более того, он мало что говорит о , в котором работает non-bash shell.

  • Метод $(type -p) очень прост и работает, даже есликакой-то мудрец создает файл с именем "-p" в вашем $PATH.Кроме того, его можно использовать в качестве основы для четырехсторонней дискриминации, или 80% от пятисторонней дискриминации, как описано ниже.

  • Установка хэш-бэнга, т. Е. #! в верхней части вашего скрипта не гарантирует, что он будет передан выбранному вами интерпретатору.Например, мой ~/.xinitrc интерпретируется как /bin/sh независимо от того, какой хэш-бэнг (если таковой имеется) появляется вверху.

  • Хорошей практикой является проверка некоторой функции, которая надежно существуетна обоих языках, но ведет себя по-разному.Напротив, было бы не в целом безопасно использовать нужную функцию и посмотреть, не сработает ли она.Например, если вы хотите использовать встроенную функцию declare, а ее нет, она может запустить программу, которая имеет неограниченный потенциал понижения.

  • Иногда целесообразно написать совместимыйкод, использующий набор функций с наименьшим общим знаменателем ... но иногда это не так.Большинство из этих добавленных функций были добавлены по причине.Поскольку эти интерпретаторы «почти» полны по Тьюрингу, «почти» гарантированно можно эмулировать одно с другим ... возможно, но не разумно.
  • Существует два уровня несовместимости: синтаксис и семантика,Например, синтаксис if-then-else для csh настолько отличается от bash, что единственный способ написать совместимый код - вообще обойтись без операторов if-then-else.Это возможно, но это требует больших затрат.Если синтаксис неправильный, скрипт не будет выполняться вообще.Как только вы преодолеете это препятствие, существует множество способов, которыми разумно выглядящий код дает разные результаты, в зависимости от того, какой диалект интерпретатора работает.
  • Для большой и сложной программы это не такимеет смысл написать две версии.Напишите это один раз, на языке по вашему выбору.Если кто-то запускает его с неверным переводчиком, вы можете обнаружить его и просто exec правильный переводчик.

  • Здесь можно найти 5-позиционный детектор:

    https://www.av8n.com/computer/shell-dialect-detect

    Может различать:

    • bash
    • bsd-csh
    • тире
    • ksh93
    • zsh5

    Кроме того, на моей коробке Ubuntu Xenial эта 5-сторонняя проверка также охватывает следующее:

    • ash - символическая ссылка на dash
    • csh - символическая ссылка на / bin / bsd-csh
    • ksh - символическая ссылка на / bin / ksh93
    • sh - символическая ссылка на тире
3 голосов
/ 22 января 2016

Я думаю, что это будет наиболее практичным и совместимым с кросс-оболочкой

/proc/self/exe --version 2>/dev/null | grep -q 'GNU bash' && USING_BASH=true || USING_BASH=false

Пояснение:

/proc/self всегда будет указывать на текущий выполняющийся процесс, например, при выполнении следующего откроется pid readlink само по себе (не оболочка, которая выполнила readlink)

$ bash -c 'echo "The shell pid = $$"; echo -n "readlink (subprocess) pid = "; readlink /proc/self; echo "And again the running shells pid = $$"'

Результаты:

The shell pid = 34233
readlink (subprocess) pid = 34234
And again the running shells pid = 34233

Сейчас: /proc/self/exe является символической ссылкой на исполняемый файл

Пример:

bash -c 'echo -n "readlink binary = "; readlink /proc/self/exe; echo -n "shell binary = "; readlink /proc/$$/exe'

Результат:

readlink binary = /bin/readlink
shell binary = /bin/bash

А вот результаты, запускаемые в dash и zsh, и запускающие bash через символическую ссылку и даже через копию.

aron@aron:~$ cp /bin/bash ./my_bash_copy
aron@aron:~$ ln -s /bin/bash ./hello_bash
aron@aron:~$ 

aron@aron:~$ dash -c '/proc/self/exe -c "readlink /proc/$$/exe"; zsh -c "/proc/self/exe --version"; ./hello_bash --version | grep bash; ./my_bash_copy --version | grep bash'
/bin/dash
zsh 5.0.7 (x86_64-pc-linux-gnu)
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
aron@aron:~$ dash -c '/proc/self/exe -c "readlink /proc/$$/exe"; zsh -c "/proc/self/exe --version"; ./hello_bash --version | grep bash; ./my_bash_copy --version | grep bash'
1 голос
/ 08 июля 2010

Переменная окружения SHELL сообщит вам, какая оболочка входа работает.

Кроме того, вы можете использовать ps $$, чтобы найти текущую оболочку, которую можно использовать, если вы хотите знать, в какой оболочке выполняется скрипт (не обязательно оболочка входа в систему). Чтобы свести вывод ps к имени только оболочки: ps o command= $$ (не уверен, насколько это кроссплатформенно безопасно, но он работает на Mac OS X).

0 голосов
/ 15 января 2013

Я бы порекомендовал попытаться обнаружить наличие необходимой вам функции , а не bash против zsh против и т. Д. Если функция присутствует, используйте ее, если не используете альтернативу. Если нет другого способа обнаружить эту функцию, кроме как использовать ее и проверять на наличие ошибок, то, хотя это довольно уродливо, у меня нет лучшего решения. Важно то, что он должен работать более надежно, чем пытаться обнаружить bash. А поскольку другие оболочки (которые все еще находятся в разработке) могут иметь эту функцию, ранее существовавшую только в bash, в какой-то момент в будущем, она действительно имеет дело с тем, что имеет значение, и позволяет избежать необходимости поддерживать базу данных о том, какие версии каждой оболочки поддержка какой функции, а какая нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...