Определенно определите, является ли запущенная оболочка bash или zsh

Как я могу окончательно определить, является ли запущенная оболочка bash или zsh?

(возможность устранения неоднозначности между дополнительными оболочками является бонусом, но только bash & zsh необходимы на 100%)

Я видел несколько способов предположительно сделать это, но у всех есть проблемы (см. Ниже).

Лучшее, что я могу придумать, - это запустить какой-нибудь синтаксис, который будет работать с одним, а не с другим, и затем проверить ошибки / выходные данные, чтобы увидеть, какая оболочка работает. Если это лучшее решение, какая команда подойдет для этого теста?

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

Неопределенные способы определения текущей запущенной оболочки:

# default shell, not current shell
basename "${SHELL}"

# current script rather than current shell
basename "${0}"

# BASH_VERSINFO could be defined in any shell, including zsh
if [ -z "${BASH_VERSINFO+x}" ]; then
    echo 'zsh'
else
    echo 'bash'
fi

# executable could have been renamed; ps isn't a builtin
shell_name="$(ps -o comm= -p $$)"
echo "${shell_name##*[[:cntrl:][:punct:][:space:]]}"

# scripts can be sourced / run by any shell regardless of shebang
# shebang parsing

Всего 4 ответа


В командной строке $ запустите:

echo $0

но вы не можете использовать $0 внутри скрипта, так как $0 станет script's name самого script's name .

Чтобы найти текущую оболочку (скажем, BASH), если исполняемый файл shebang / magic number был #!/bin/bash внутри скрипта:

#!/bin/bash
echo "Script is: $0 running using $$ PID"
echo "Current shell used within the script is: `readlink /proc/$$/exe`"

script_shell="$(readlink /proc/$$/exe | sed "s/.*///")"

echo -e "
SHELL is = ${script_shell}
" 

if [[ "${script_shell}" == "bash" ]]
then
    echo -e "
I'm BASH
"
fi

Выходы:

Script is: /tmp/2.sh running using 9808 PID
Current shell used within the script is: /usr/bin/bash

SHELL is = bash

I'm BASH

Это будет работать, если shebang был: #!/bin/zsh (также).

Затем вы получите вывод для SHELL:

SHELL is = zsh

Хотя не существует 100% надежного способа достижения этого, это может помочь

echo $BASH_VERSION
echo $ZSH_VERSION

Оба являются переменными оболочки (не переменными среды), которые устанавливаются соответствующей оболочкой. В соответствующей другой оболочке они пусты.

Конечно, если кто-то намеренно создает переменную с таким именем или экспортирует такую ​​переменную, а затем создает подоболочку другого типа, т.е.

# We are in bash here
export BASH_VERSION 
zsh  # the subshell will see BASH_VERSION even though it is zsh

этот подход потерпит неудачу; но я думаю, что если кто-то действительно так поступает, он намеренно саботирует ваш код.


Работая на основе комментариев @ruakh & @oguzismail, я думаю, что у меня есть решение.

Если кто-нибудь увидит какие-либо проблемы с решением, приведенным ниже (оно отлично работает на выпусках zsh 5.8 и bash 5.0.16 (1), оба на macOS 10.15.4), пожалуйста, дайте мне знать.

В противном случае, если никто не сообщит о проблемах в течение нескольких дней, я приму этот ответ как правильное решение.

shell_name="$(builtin shopt -u lastpipe 2> /dev/null || builtin return 1 2> /dev/null; builtin echo 'bash')" 2> /dev/null
shell_name="${shell_name:-zsh}"

Это должно работать для большинства систем Linux:

cat /proc/$$/comm

Быстро и просто.


Есть идеи?

10000