Как мне * надежно * и * просто * получить текущее имя интерпретатора оболочки?

9

Я ищу простой и надежный способ получить имя текущей оболочки из скрипта или файла источника ( не из командной строки). Я хотел бы просто сделать, $(basename "$SHELL")но если моя оболочка входа в систему zshи у меня есть следующий код в some_script.sh

this_shell=$( basename "$SHELL" )
echo "The Shell is $this_shell"
echo "The Shell is $0"

и я запускаю его bash some_script.sh, он по-прежнему перечисляет zshвместо того, bashчтобы использовать интерпретатор /bin/bash. Я не уверен, почему разработчики оболочек решили показывать оболочку по умолчанию вместо текущей, но, похоже, это то, с чем мы застряли.

Есть и другие слегка похожие вопросы ( здесь и здесь ), но их ответы во многом не отвечают.

  1. Они часто предполагают, что пользователь пытается выяснить, какую интерактивную оболочку они используют в настоящее время, но это безумие. Я знаю, в какую оболочку я набираю команды - мне нужен код, который можно запустить где угодно, чтобы определить, какую оболочку он использует.
  2. Они часто дают несколько разных вещей, чтобы попробовать - опять же, как будто вы находитесь в командной строке и можете просто возиться, пока не узнаете, что используете bash - но мне нужна одна вещь, которая была бы надежной во всех контекстах.
  3. Они часто дают вещи, которые совершенно бесполезны из сценариев, например echo $0. Это не так, как показано в сценарии выше. (Да, он работает в командной строке интерактивной оболочки, но почему бы вам никогда не узнать, какую оболочку вы используете?)
  4. Иногда они дают команды, которые (в моих ограниченных тестах) включают в себя правильную информацию, например ps -p $$, но не имеют кросс-платформенных, совместимых с оболочкой команд sed / awk, чтобы передать их, чтобы получить только имя оболочки и игнорировать другую информацию, которая появляется для езды.
  5. Они включают в себя вещи, которые будут работать только на пару оболочек, как $BASH_VERSIONи $ZSH_VERSION. Я хочу поддержать как много раковин , насколько это возможно, например fish, csh, tcsh.

Как мне надежно и точно обнаружить любую текущую оболочку? Я ищу что-то, что будет работать на разных платформах, в скриптах и ​​для максимально возможного количества оболочек 1 .

ОБНОВЛЕНИЕ : Когда я отправил этот вопрос, я ожидал, что в снарядах был встроен какой-то объект, чтобы дать нам эту информацию, что, похоже, не так. Поскольку теперь кажется неизбежным полагаться на что-то за пределами оболочек, я должен более четко указать, что я прошу кросс-платформенное решение (которое, хотя и вытекает из моих возражений на другие ответы выше, может быть легко пропустить, если вы не не читайте вопрос внимательно).

Обновление 2 Если кто-то все еще считает, что это дубликат вопроса, касающегося только Linux, поскольку ответ Стефана не только на Linux, то здесь есть различия между тем, что я прошу, и тем, что он предоставил. (Обратите внимание, что то, что он написал, было гениальным, и я его не сбиваю, но это не решает мою проблему.)

  1. Я ищу что-то простое и надежное , что
  2. могут быть добавлены в любое определение сценария или функции (которые будут получены с помощью .zshrcили .bash_profileили любой другой ) в отрасли.
  3. Вы не можете использовать его сценарий как внешнюю утилиту, которая передает имя интерпретатора вызывающему сценарию / функции, поскольку оно всегда будет интерпретироваться интерпретатором по умолчанию и возвращать его. Это затрудняет или делает невозможным использование в моих целях. Если это возможно, это все еще очень, очень сложно, и решение для того, чтобы заставить это работать, не дано в ответе. Поэтому он не ответил на мой вопрос, поэтому он не является дубликатом.

Если вы хотите увидеть что-то, что будет работать, взгляните на ShellDetective на GitHub . Это может облегчить понимание различий между тем, что уже присутствует на SE, и тем, что ищет этот вопрос (и был фактически написан для того, чтобы удовлетворить потребности этого вопроса, которые не были удовлетворены где-либо еще).


(PS Если вы не можете поверить, что для этого есть сценарий использования, представьте себе, какие функции .zshrcиспользуются .bash_profile, или в .profileзависимости от того, какой сервер используется и какие оболочки у него есть. Они получены, поэтому у них нет строки Шебанга. Они наиболее полезны, если они могут работать в любой оболочке, но иногда они должны знать, в какой оболочке они находятся, чтобы знать, как себя вести.)


1 Меня не интересуют «раковины», которые не являются раковинами в каком-либо традиционном смысле этого слова. Меня не волнует какая-то оболочка, которую какой-то парень написал для себя. Я имею дело только с реальными оболочками, которые на самом деле встречаются в дикой природе и которые кто-то может использовать при входе на какой-либо сервер, на котором они не могут просто установить какие-либо оболочки, которые они хотят.

иконоборец
источник
Прочитать полностью не по теме обсуждение того, является ли Python оболочкой: см. Здесь
iconoclast
2
Цитирование Жиль «сек ответ на вопрос Что такое точное различие между„терминал“, а„оболочка“, а„терминал“и„Консоль“?   - « Оболочка - это основной интерфейс, который видят пользователи при входе в систему и который предназначен для запуска других программ». ИМО, этого достаточно, чтобы исключить Perl и Python из категории «оболочка».
G-Man говорит: «Восстановите Монику»
Смутно связано: Совместимость скриптов: Save $? для использования позже . Предлагаемый подход: обойти различия в синтаксисе различных оболочек, сказав sh -c "…", а затем выполнить основную часть работы в синтаксисе оболочки POSIX.
G-Man говорит: «Восстановите Монику»
2
Почему ты хочешь получить это ? Некоторые оболочки, используемые в качестве оболочек для входа, имеют очень несовместимый синтаксис (некоторые оболочки являются языками, подобными Lisp!), Поэтому я не понимаю, почему вы хотите это сделать. Если вы кодируете исходные файлы, вам нужно будет кодировать несколько вариантов и предложить своему пользователю выбрать подходящий.
Василий Старынкевич
1
Мой второй вопрос - пример маскировки оболочки. Что делать, если скрипт выполняется исполняемым файлом интерпретатора, имя которого не соответствует языку, который интерпретирует интерпретатор? Если я возьму копию csh, переименую ее fishи использую для запуска скрипта, вы хотите fishили csh?
Жиль "ТАК - перестань быть злым"

Ответы:

5

У меня были отличные результаты с этой комбинацией:

ps -p $$ | awk '$1 != "PID" {print $(NF)}'

На Tru64 (OSF / 1) вывод содержит круглые скобки вокруг оболочки. Нажмите, tr -d '()'чтобы удалить их.

ps -p $$ | awk '$1 != "PID" {print $(NF)}' | tr -d '()'  

Появляется на всех оболочках, на Solaris 10 и RHEL 5.7 / 6.4. Не тестировал другие дистрибутивы, такие как Debian, Ubuntu или Mint, но я думаю, они все должны работать одинаково; Я также понятия не имею, будет ли работать FreeBSD.

введите описание изображения здесь

Крис Эмбри
источник
3
Не работает в сценариях (вместо этого возвращает имя сценария)
Qw3ry
2

Так что я все еще пытаюсь уточнить это, но я думаю, у меня есть идея, которая будет работать. Как вы заметили, то, что вы пытаетесь сделать, если не невозможно, то чрезвычайно сложно сделать во всех оболочках (каждый вариант, который вы добавляете в полиглот, увеличивает сложность с большей линейной скоростью). вы могли бы сделать это, если бы вы разбились на Bourne (sh, ash, dash, bash, ksh, pdksh, zsh и т. д.) и оболочки в стиле c (csh, tcsh, fish и т. д.), но различия между cshвариантами представляют различные интересные вызовы.

Итак, давайте изменим и напишем нашу процедуру обнаружения на известном языке (bash со строкой shebang, C, perl, python и т. Д.) И определим имя исполняемого файла родителя. затем мы можем использовать два трюка, чтобы вернуть информацию родителю, а именно: возвращаемое значение (я) и одно слово, записанное для стандартного вывода. На sh спустившихся оболочках мы возвращали бы 0 и записывали имя оболочки, так как все они имеют хорошую обработку обратного удара. в семействе оболочек C мы можем начать увеличивать возвращаемое значение для каждого набора несовместимостей, который нам нужно обойти. Возвращаемые значения более двухсот указали бы на ошибки, начиная со всего, что кажется нормальным, но я просто не могу сказать, кто мой родитель на двухстах.

Внутренняя программа на Linux выглядит просто ( /proc/ppid/exeэто полдела). Я почти уверен, что это можно сделать на bsd с опциями ps, но на данный момент у меня нет работающей системы bsd для тестирования, и моему компьютеру Mac нужен новый жесткий диск (и в любом случае его всего 10.4). Хотя это значительно уменьшает проблемы с синтаксисом оболочки, он представляет другой набор проблем совместимости. Я все еще думаю, что у него есть возможности.

hildred
источник
Это понимание, с которым я в конечном итоге остановился - что вам нужна внешняя программа для выполнения работы - хотя я получил ее, когда прочитал комментарий G-Man sh -c "...", который он взял из другого вопроса . (Извините: я сначала пропустил ваш ответ, потому что не увидел в нем никакого кода, а только вернулся и прочитал его позже.)
iconoclast
В вопросе @ iconoclast есть парадокс. Он хочет вызвать это из сценария (обратите внимание, что некоторые оболочки не поддерживают функции), который может быть получен из любой оболочки, так что сценарий, по-видимому, уже является полиглотом, поэтому уже должен иметь некоторую поддержку для выяснения того, что его интерпретирует. По моему опыту, написание кода polyglot (мой which_intepreter - крайний пример, но найти там только оболочку очень сложно и, как правило, не стоит усилий.
Стефан Шазелас
@ StéphaneChazelas: Я думаю, что вы правы, что это, как правило, не стоит усилий (конечно, обычно нет, и, возможно, всегда нет), но я не готов сдаваться ... Я думаю, что проблема разбивается на 2 проблемы на самом деле: 1-й получить имя оболочки, и второе, используя его. Оба (по крайней мере, на практике) требуют некоторой внешней помощи, чтобы избежать ограничений оболочек, которые вы могли бы использовать. Я решил первую проблему с помощью небольшой утилиты, написанной на Crystal, и когда я найду время, я хочу решить и 2-ю. Кстати, ваше решение блестящее, но, очевидно, очень сложное.
иконоборчество
@iconoclas, при условии, что вы можете надежно извлечь имя оболочки (обратите внимание, что подстановка команд и синтаксис назначения переменных варьируется между оболочками), вы не можете делать что-то вроде case $shell in sh)...(это только синтаксис Bourne) или switch ($shell)(только csh). test "$shell" = "sh" && do-somethingработает в csh/ sh/ rc/ es, но не fish...
Стефан Шазелас
да, я уже столкнулся с этим. Хуже всего то, что fish даже не загружает скрипт с синтаксисом, который ему не нравится, поэтому вы не можете просто отправить STDERR /dev/null. Но у меня есть решение, которое я опубликую, как только у меня все заработает.
иконоборчество
1

попробуйте что-нибудь подобное

shell_bin=$(ps h -p $$ -o args='' | cut -f1 -d' ')
echo $shell_bin
Дэни Флорес
источник
Это не в cshи tcsh.
иконоборчество
с небольшой модификацией он будет работать в fish, но только fish, к сожалению: ps h -p %self -o args='' | cut -f1 -d' '. Это создает проблему с курицей и яйцом ... вы должны знать, что вы находитесь fish, чтобы выполнить fishверсию кода ...
iconoclast
@ iconoclast- set shell_bin=`ps -p $$ -o args='' | cut -f1 -d' '`- будет работать с CSH, но не с другими
DarkHeart
@DarkHeart: на самом деле это не удается, так как присваивание переменной не было проблемой на csh/ tcsh, то эта часть: ps -p $$ -o args='' | cut -f1 -d' ', которая возвращается -shна cshи -cshна tcsh.
иконоборчество
1

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

В дистрибутивах Linux большинство пользователей используют в bash качестве логина и интерактивной оболочки (так bashкак это оболочка по умолчанию в большинстве дистрибутивов). Некоторые пользователи будут устанавливать свою оболочку для zsh, csh(и варианты) или fish.

(Как и другие комментарии и ответы объяснить, найти надежную оболочку из bash, zsh, tcsh, fishуже вызова)

Но некоторые странные пользователи могут установить их оболочку входа в нечто совершенно другое - интерпретатор Лиспа, scsh, es, некоторый язык сценариев а - ля Python или OCaml, или Perl, и т.д. ...- и это их свобода сделать это. Возможно, некоторые люди кодируют свою собственную оболочку и используют ее в интерактивном режиме. Даже если вы нашли их странную оболочку, вы не сможете ничего с ней поделать (поэтому я считаю, что вам не следует пытаться получить имя оболочки).

Поэтому я предполагаю, что вы кодируете какой-то исходный файл (возможно, генерирующий один) для настройки некоторого программного обеспечения. Так что просто объясните, что вы делаете, и напишите для общего случая bash(и, возможно, zsh& tcsh) ....

Василий Старынкевич
источник
-2

использовать ниже на свой страх и риск

tmp=`head -n 1 $0`
SHELL_BIN=`readlink -f ${tmp#*!}`
SHELL=${SHELL_BIN##*/}
gwillie
источник
это дает мне пустую строку ... но если я понимаю, что вы пытаетесь сделать, это очень умно
иконоборчество
Он не должен давать вам пустую строку, если не -freadlink
указан
Я нахожусь на OS X, и страница руководства перечисляет -fкак доступную опцию, принимая в formatкачестве аргумента.
иконоборчество
Это может работать в некоторых особых случаях, если $ 0 - это скрипт (начинается с #! / ...), но это не обычная установка. Здесь большинство $ 0 указывают на файл ELF.
readlinkне работает на моем puredarwin vm, так что я не знаю, что там происходит.
Гвилли