Как я могу определить текущую оболочку, над которой я работаю?
Достаточно ли вывода команды ps?
Как это можно сделать в разных вариантах UNIX?
Как я могу определить текущую оболочку, над которой я работаю?
Достаточно ли вывода команды ps?
Как это можно сделать в разных вариантах UNIX?
Существует 3 подхода к поиску имени текущего исполняемого файла оболочки:
Обратите внимание, что все три подхода могут быть обмануты, если исполняемый файл оболочки /bin/sh, но он действительно переименован, например, (t21) (что часто происходит).
Таким образом, ваш второй вопрос о том, будет ли выводиться вывод ps, будет отвечать " не всегда".
 echo $0 - напечатает имя программы... которое в случае оболочки является реальной оболочкой
 ps -ef | grep $$ | grep -v grep - Это будет искать текущий идентификатор процесса в списке запущенных процессов. Поскольку текущий процесс является оболочкой, он будет включен.
Это не на 100% надежнее, так как у вас могут быть ДРУГИЕ процессы, чей список ps содержит тот же номер, что и идентификатор процесса оболочки, особенно если этот идентификатор является небольшим # (например, если PID оболочки равен "5", вы можете найти процессы, называемые "java5" или "perl5", в том же выпуске grep!). Это вторая проблема с подходом "ps", не имея возможности полагаться на имя оболочки.
 echo $SHELL - Путь к текущей оболочке сохраняется как переменная SHELL для любой оболочки. Предостережение для этого заключается в том, что если вы запускаете оболочку явно как подпроцесс (например, это не ваша оболочка для входа), вы получите вместо этого значение своей учетной записи. Если это возможно, используйте подход ps или $0.
Если, однако, исполняемый файл не соответствует вашей реальной оболочке (например, /bin/sh на самом деле bash или ksh), вам нужна эвристика. Вот некоторые экологические переменные, характерные для разных оболочек:
 $version устанавливается на tcsh
 $BASH установлен на bash
 $shell (в нижнем регистре) устанавливается фактическое имя оболочки в csh или tcsh
 $ZSH_NAME установлен на zsh
ksh имеет $PS3 и $PS4 set, тогда как обычная оболочка Bourne (sh) имеет только $PS1 и $PS2. Это, как правило, кажется наиболее сложным - единственная разница во всем наборе переменных envionmental между sh и ksh, которые мы установили на Solaris boxen, - это $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, $TMOUT.
 ps -p $$
должен работать в любом месте, где выполняются решения с участием ps -ef и grep (в любом варианте Unix, который поддерживает параметры POSIX для ps) и не будет страдать от ложных срабатываний, введенных grepping для последовательности цифр, которые могут появляться в другом месте.
Try
ps -p $$ -oargs=
или
ps -p $$ -ocomm=
Если вы просто хотите, чтобы пользователь вызывал script с помощью bash:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
Вы можете попробовать:
ps | grep `echo $$` | awk '{ print $4 }'
Или:
echo $SHELL
 $SHELL не всегда нужно отображать текущую оболочку. Он отображает только оболочку по умолчанию, которую нужно вызвать.
Чтобы проверить выше, Say bash является оболочкой по умолчанию, попробуйте echo $SHELL, затем в том же терминале, перейдите в другую оболочку (например, ksh) и попробуйте $SHELL, вы увидите результат как bash в обоих случаях.
Чтобы получить имя текущей оболочки, используйте cat /proc/$$/cmdline И путь к исполняемому файлу оболочки readlink /proc/$$/exe
ps - самый надежный метод. Экран SHELL не может быть установлен, и даже если он есть, его можно легко подделать
У меня есть простой трюк, чтобы найти текущую оболочку. Просто введите случайную строку (которая не является командой). Он потерпит неудачу и вернет ошибку "не найден", но в начале строки он скажет, какая оболочка это:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Это всегда даст фактическую используемую оболочку - получает имя фактического исполняемого файла, а не имя оболочки (т.е. ksh93 вместо ksh и т.д.). Для /bin/sh будет отображаться фактическая используемая оболочка: т.е. dash
ls -l /proc/$$/exe | sed 's%.*/%%'
Я знаю, что многие говорят, что вывод ls должен обрабатываться по-новому, но какова вероятность того, что у вас будет оболочка, которую вы используете с именами со специальными символами или поместите в каталог с именами со специальными символами? Если это так, то есть много других примеров, делающих это по-другому.
ОБНОВЛЕНИЕ: как указал Тоби Спейт, это был бы более правильный и более чистый способ достижения того же самого:
basename $(readlink /proc/$$/exe)
Я пробовал много разных подходов, и лучший для меня:
 ps -p $$
Он также работает под Cygwin и не может создавать ложные срабатывания в качестве PID grepping. С некоторой очисткой он выводит только исполняемое имя (под Cygwin с путём):
ps -p $$ | tail -1 | awk '{print $NF}'
Вы можете создать функцию, поэтому вам не нужно ее запоминать:
# print currently active shell
shell () {
  ps -p $$ | tail -1 | awk '{print $NF}'
}
... и просто выполните shell.
Протестировано под Debian и Cygwin.
Мой вариант при печати родительского процесса.
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Зачем запускать ненужные приложения, когда "awk" может сделать это за вас?
Если ваш /bin/sh поддерживает стандарт POSIX, и ваша система имеет установленную команду lsof - возможная альтернатива lsof в этом случае может быть pid2path - вы также можете использовать (или адаптировать) следующие script, который печатает полные пути:
#!/bin/sh
# cat /usr/local/bin/cursh
set -eu
pid="$$"
set -- sh bash zsh ksh ash dash csh tcsh pdksh mksh fish psh rc scsh bournesh wish Wish login
unset echo env sed ps lsof awk getconf
# getconf _POSIX_VERSION  # reliable test for availability of POSIX system?
PATH="`PATH=/usr/bin:/bin:/usr/sbin:/sbin getconf PATH`"
[ $? -ne 0 ] && { echo "'getconf PATH' failed"; exit 1; }
export PATH
cmd="lsof"
env -i PATH="${PATH}" type "$cmd" 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
awkstr="`echo "[email protected]" | sed 's/\([^ ]\{1,\}\)/|\/\1/g; s/ /$/g' | sed 's/^|//; s/$/$/'`"
ppid="`env -i PATH="${PATH}" ps -p $pid -o ppid=`"
[ "${ppid}"X = ""X ] && { echo "no ppid found"; exit 1; }
lsofstr="`lsof -p $ppid`" || 
   { printf "%s\n" "lsof failed" "try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; }
printf "%s\n" "${lsofstr}" | 
   LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}'
echo $$ # Gives the Parent Process ID 
ps -ef | grep $$ | awk '{print $8}' #use the PID to see what the process is.
Ни один из ответов не работал с оболочкой fish (у нее нет переменных $$ или $0).
Это работает для меня (проверено на sh, bash, fish, ksh, csh, true, tcsh и zsh; openSUSE 13.2):
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
Эта команда выводит строку типа bash. Я использую здесь только ps, tail и sed (без GNU extesions, попробуйте добавить --posix, чтобы проверить его). Все они являются стандартными командами POSIX. Я уверен, что tail можно удалить, но мой sed fu недостаточно силен, чтобы сделать это.
Мне кажется, что это решение не очень портативно, так как оно не работает на OS X.: (
Существует множество способов узнать оболочку и ее соответствующую версию. Вот несколько из них, которые работали для меня.
Прямо вперед
Хакский подход
$ > ******* (Введите набор случайных символов, а на выходе вы получите имя оболочки. В моем случае - bash: chapter2-a-sample-isomorphic-app: command not найдено)
В Mac OS X (& FreeBSD):
ps -p $$ -axco command | sed -n '$p' 
Если вы просто хотите проверить, что вы работаете (конкретная версия) Bash,
лучший способ сделать это - использовать переменную массива $BASH_VERSINFO.
Как переменная массива (только для чтения) она не может быть установлена в среде,
поэтому вы можете быть уверены, что он придет (если вообще) из текущей оболочки.
Однако, поскольку Bash имеет другое поведение при вызове sh,
вам также нужно проверить, что переменная среды $BASH заканчивается на /bash.
В script я написал, что использует имена функций с - (не подчеркивает)
и зависит от ассоциативных массивов (добавлено в Bash 4),
У меня есть следующая проверка работоспособности (с полезным сообщением об ошибке пользователя):
case `eval 'echo [email protected]${BASH_VERSINFO[0]}' 2>/dev/null` in
    */[email protected][456789])
        # Claims bash version 4+, check for func-names and associative arrays
        if ! eval "declare -A _ARRAY && func-name() { :; }" 2>/dev/null; then
            echo >&2 "bash $BASH_VERSION is not supported (not really bash?)"
            exit 1
        fi
        ;;
    */[email protected][123])
        echo >&2 "bash $BASH_VERSION is not supported (version 4+ required)"
        exit 1
        ;;
    *)
        echo >&2 "This script requires BASH (version 4+) - not regular sh"
        echo >&2 "Re-run as \"bash $CMD\" for proper operation"
        exit 1
        ;;
esac
Вы можете опустить несколько параноидальную функциональную проверку функций в первом случае, и просто предположим, что будущие версии Bash будут совместимы.
Grepping PID с выхода "ps" не требуется, потому что вы можете прочитать соответствующую командную строку для любой структуры каталога PID из /proc:
echo $(cat /proc/$$/cmdline)
Однако это может быть не лучше, чем просто:
echo $0
О запуске фактически другой оболочки, чем указано в названии, одна идея состоит в том, чтобы запросить версию из оболочки с использованием ранее полученного имени:
<some_shell> --version
sh, похоже, терпит неудачу с кодом выхода 2, а другие дают что-то полезное (но я не могу проверить все, так как у меня их нет):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Это не очень чистое решение, но делает то, что вы хотите.
Я понимаю, что ответ немного поздний в этом добром старом 2015 году, но...
#MUST BE SOURCED..
getshell() {
    local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"
    shells_array=(
    # It is important that the shells are listed by the decrease of their length name.
        pdksh
        bash dash mksh
        zsh ksh
        sh
    )
    local suited=false
    for i in ${shells_array[*]}; do
        if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
            shell=$i
            suited=true
        fi
    done
    echo $shell
}
getshell
Теперь вы можете использовать
$(getshell) --version.
Это работает, однако, только для ksh-подобных оболочек.
Мое решение:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
Это должно быть переносимо для разных платформ и оболочек. Он использует ps как другие решения, но не полагается на sed или awk и отфильтровывает мусор из трубопровода и ps сам, поэтому оболочка всегда должна быть последней записью. Таким образом, нам не нужно полагаться на непереносимые переменные PID или выбирать правильные строки и столбцы.
Я тестировал на Debian и MacOS с помощью bash, zsh и fish (что не работает с большинством этих решений без изменения выражения специально для рыбы, поскольку оно использует другую переменную PID).
Чтобы узнать, использует ли ваша оболочка DASH/BASH, выполните следующие действия.
1) ls –la/bin/sh, если результат /bin/sh ->/bin/bash ==> Тогда ваша оболочка использует BASH.
если результат /bin/sh ->/bin/dash ==> Тогда ваша оболочка использует DASH.
Если вы хотите перейти с BASH на DASH или наоборот, используйте следующий код ln -s/bin/bash/bin/sh (изменить оболочку на BASH)
ПРИМЕЧАНИЕ. Если приведенная выше команда выдает сообщение об ошибке: /bin/sh уже существует, удалите /bin/sh и повторите попытку.
Пожалуйста, используйте следующую команду:
 # ps -p $$ | tail -1 | awk '{print $4}'
Этот хорошо работает на RHEL, MacOS, BSD и некоторых AIX
ps -T $$ | awk 'NR==2{print $NF}' 
альтернативно, следующий также должен работать, если pstree доступен,
pstree | egrep $$ | awk 'NR==2{print $NF}'