2010-07-08 3 views
8

Сценарий является то, что пользователи просят источника файл сценария:HOWTO: Обнаружение Баш из сценария оболочки

$ source envsetup.sh 

Этот файл сценария может использовать Баш особенность только поэтому мы должны обнаружить запуска оболочки баш или нет.

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

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

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

ответ

13

Есть куча переменных окружения, на которые вы можете смотреть, но многие из них не обнаружат, если из 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 $$. Это технически дает вам имя команды, в которой работает shell. В большинстве случаев это будет работать ... с тех пор, как приложения запускаются с некоторым вариантом системного вызова 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.

2

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

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

+0

Попробуйте это из bash, прежде чем полагаться на '$ SHELL':' csh -c 'echo "$ SHELL"' ' –

+0

Мое впечатление о том, что скрипт должен знать оболочку входа. Используя bash в качестве оболочки входа, запуск этой команды должен вернуть bash, что и ожидается. – Jeff

+0

Не оболочка входа. Если вы входите в систему, используйте bash, затем переключитесь на csh, $ SHELL останется bash, но 'source' будет терпеть неудачу. –

10

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

[ -z "$BASH_VERSION" ] && return 
+1

Может также сделать это для zsh, поэтому 'if [-n" $ {BASH_VERSION} "]; затем ... elif [-n "$ {ZSH_VERSION}"]; то ... fi' –

+0

имеют сценарий: '#!/bin/sh \ n echo $ BASH_VERSION' и даже запускать его с sh или csh из оболочки bash:' $ sh./test.sh', и вы получите env var от пользователя предпочитает версию bash ....полностью вводящий в заблуждение сценарий работы – gcb

1

Что мешает вам писать переносимый (оболочки независимый т.) Сценарий?

+0

Потому что upstream очень сильно полагается на него. Это не то, что я могу контролировать ;-) –

+0

Значит, вы немного исправляете существующие скрипты для некоторого распространения? –

+0

Из любопытства, какие особенности, связанные с bash, могут использоваться 'envsetup.sh'? Я бы предположил, что он содержит только некоторые выражения 'export A = B' ... –

0

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

2

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

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

Объяснение:

/proc/self всегда будет указывать на текущий выполняющемся процесс, например, выполнив следующие действия показывают идентификатор процесса от 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 

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

[email protected]:~$ cp /bin/bash ./my_bash_copy 
[email protected]:~$ ln -s /bin/bash ./hello_bash 
[email protected]:~$ 

[email protected]:~$ 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) 
[email protected]:~$ 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' 
4

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

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

, и вы, конечно, можете заменить «эхо» заявления с чем угодно.

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

Обсуждение:

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

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

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

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

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

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

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

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

    Он может различать:

    • Баш
    • BSD-CSH
    • тире
    • ksh93
    • zsh5

    Кроме того, на моей машине Ubuntu дружественной, что 5-позиционная проверка также включает в себя следующую:

    • зола является символической ринуться
    • CSH является символической ссылкой на/bin/BSD -csh
    • КШ является символической ссылкой на/bin/ksh93
    • ш является символическим ринуться
Смежные вопросы