Как определить текущую оболочку, над которой я работаю?

Как определить текущую оболочку, над которой я работаю?

будет выводить ps достаточно одной команды?

Как это можно сделать в разных вариантах UNIX?

23 ответов


  • есть 3 подхода к нахождению имя исполняемого файла текущей оболочки:

    обратите внимание, что все 3 подхода можно обмануть, если исполняемый файл оболочки /bin/sh но это действительно переименован bash, например (что часто бывает).

    таким образом ваш второй вопрос о том,ps выход будет делать ответ с "не всегда".

    1. echo - напечатает имя программы... который в случае shell является фактическим shell

    2. ps -ef | grep $$ | grep -v grep - это будет искать текущий идентификатор процесса в списке запущенных процессов. Поскольку текущий процесс является shell, он будет включен.

      это не на 100% надежно, так как у вас могут быть другие процессы, чьи ps листинг включает в себя тот же номер, что и идентификатор процесса оболочки, особенно если этот идентификатор небольшой # (например, если PID оболочки "5", Вы можете найти процессы под названием "java5" или "perl5" в том же grep выход!). это вторая проблема с подходом "ps", Помимо невозможности полагаться на имя оболочки.

    3. echo $SHELL - путь к текущей оболочке сохраняется как SHELL переменная для любой оболочки. Предостережение для этого заключается в том, что если вы запускаете оболочку явно как подпроцесс (например, это не ваша оболочка входа), вместо этого вы получите значение login shell. Если это возможно, используйте ps или подход.


  • Если, однако, исполняемый файл не соответствует вашей фактической оболочке (например,/bin/sh на самом деле bash или ksh), вам нужна эвристика. Вот некоторые переменные среды, характерные для различных оболочек:

    • $version установлен на tcsh

    • $BASH на Баш

    • $shell (нижний регистр) имеет значение фактическое имя оболочки в csh или tcsh

    • $ZSH_NAME установлен на zsh

    • ksh имеет $PS3 и $PS4 set, тогда как нормальная оболочка Борна (sh) только $PS1 и $PS2 set. Это вообще кажется самым трудным отличить - единственная разница во всем наборе переменных окружающей среды между sh и ksh мы установили на Solaris Боксен-это $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, $TMOUT.


ps -p $$

должен работать в любом месте, что решения с участием ps -ef и grep do (на любом варианте Unix, который поддерживает параметры POSIX для ps) и не будет страдать от ложных срабатываний, введенных grepping для последовательности цифр, которые могут появиться в другом месте.


попробовать

ps -p $$ -oargs=

или

ps -p $$ -ocomm=

можно попробовать:

ps | grep `echo $$` | awk '{ print  }'

или:

echo $SHELL

Если вы просто хотите убедиться, что пользователь вызывает скрипт с bash:

if [ ! -n "$BASH" ] ;then echo Please run this script  with bash; exit 1; fi

$SHELL не всегда нужно показывать текущую оболочку. Он отражает только вызываемую оболочку по умолчанию.

чтобы проверить вышесказанное, скажите bash является оболочкой по умолчанию, попробовать echo $SHELL, затем в том же терминале войдите в другую оболочку (например, ksh) и попробуйте $SHELL, вы увидите результат как Bash в обоих случаях.

чтобы получить имя текущей оболочки, используйте cat /proc/$$/cmdline и путь к исполняемому файлу оболочки readlink /proc/$$/exe


ps самый надежный метод. Оболочка envar не гарантируется, и даже если это так, ее можно легко подделать


У меня есть простой трюк, чтобы найти в текущей оболочке. Просто введите случайную строку (которая не является командой). Он потерпит неудачу и вернет ошибку "не найден", но в начале строки он скажет, какая это оболочка:

ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found

это всегда будет давать фактическую используемую оболочку-получает имя фактического исполняемого файла, а не имя оболочки (т. е. ksh93 вместо ksh etc.) For /bin/sh покажет фактическую используемую оболочку: т. е. dash

ls -l /proc/$$/exe | sed 's%.*/%%'

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


мой вариант печати родительского процесса.

ps -p $$ | awk ' == PP {print }' PP=$$

зачем запускать ненужные приложения, когда " awk " может сделать это за вас?


при условии, что ваш /bin/sh поддерживает стандарт POSIX, и ваша система имеет lsof команда установлена-возможная альтернатива lsof может в этом случае быть pid2path - вы также можете использовать (или адаптировать) следующий скрипт, который выводит полный путь:

#!/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 "$@" | sed 's/\([^ ]\{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}'

Я пробовал много разных подходов, и лучший для меня:

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.


echo $$ # Gives the Parent Process ID 
ps -ef | grep $$ | awk '{print }' #use the PID to see what the process is.

от http://www.unix.com/unix-dummies-questions-answers/10390-how-do-you-know-what-your-current-shell.html


в Mac OS X (&FreeBSD):

ps -p $$ -axco command | sed -n '$p' 

если вы просто хотите проверить, что вы работаете (конкретная версия) Bash, лучший способ сделать это-использовать $BASH_VERSINFO переменной массива. В качестве переменной массива (только для чтения) ее нельзя установить в среде, таким образом, вы можете быть уверены, что он приходит (если вообще) из текущей оболочки. Однако, поскольку Bash имеет другое поведение при вызове как sh, вам также нужно проверить $BASH переменная окружения заканчивается на /bash.

в скрипте я написал, что использует имена функций с - (не подчеркнуть) и зависит от ассоциативных массивов (добавлено в Bash 4), У меня есть следующая проверка здравомыслия (с полезным сообщением об ошибке пользователя):

case `eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null` in
    */bash@[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
        ;;
    */bash@[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 

о запуске фактически другой оболочки, чем указывает имя, одна идея-запросить версию из оболочки, используя имя, которое вы получили ранее:

<some_shell> --version

sh, похоже, терпит неудачу с кодом выхода 2, в то время как другие дают что-то полезное (но Я не могу проверить все, так как у меня их нет):

$ sh --version
sh: 0: Illegal option --
echo $?
2

ни один из ответов не работал с fish shell (у него нет переменных $$ или ).

это работает для меня (проверено на sh, bash, fish, ksh, csh, true, tcsh и zsh; openSUSE 13.2):

ps | tail -n 4 | sed -E '2,$d;s/.* (.*)//'

эта команда выводит строку как bash. Я использую здесь только ps, tail и sed (без расширений GNU; попробуйте добавить --posix чтобы проверить его). Все они являются стандартными командами POSIX. Я уверен tail можно удалить, но мой sed фу недостаточно силен, чтобы сделать это.

мне кажется, что это решение не очень портативно, так как оно не работает на OS X. :(


это не очень чистое решение, но делает то, что вы хотите.

Я понимаю, что ответ немного запоздал в этом старом добром 2015 году, но...

#MUST BE SOURCED..
getshell() {
    local shell="`ps -p $$ | tail -1 | awk '{print }'`"

    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).


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

вперед

  1. $>Эхо $0 (дает вам имя программы. В моем случае выход был Баш)
  2. $>$SHELL (это приведет вас в оболочку, и в приглашении вы получите имя оболочки и версию. В моем случае bash3.2$ )
  3. $> echo $SHELL (это даст вам путь к исполняемому файлу. В моем случае / bin / bash)
  4. $>$SHELL --version (это даст полную информацию о программном обеспечении оболочки с типом лицензии)

подход программистские

$> ******* (введите набор случайных символов, и на выходе вы получите имя оболочки. В моем случае - bash: chapter2-a-sample-isomorphic-app: команда не найдено)


пожалуйста, используйте следующую команду:

 # ps -p $$ | tail -1 | awk '{print }'

сделайте следующее, чтобы узнать, использует ли ваша оболочка 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 и повторите попытку.


это хорошо работает на RHEL, MacOS, BSD и некоторых AIXes

ps -T $$ | awk 'NR==2{print $NF}' 

в качестве альтернативы, следующий также должен работать, если pstree доступен,

pstree | egrep $$ | awk 'NR==2{print $NF}'