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

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

Достаточно ли вывода команды ps?

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

Ответ 1

  • Существует 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.

Ответ 2

ps -p $$

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

Ответ 3

Try

ps -p $$ -oargs=

или

ps -p $$ -ocomm=

Ответ 4

Если вы просто хотите, чтобы пользователь вызывал script с помощью bash:

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

Ответ 5

Вы можете попробовать:

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

Или:

echo $SHELL

Ответ 6

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

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

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

Ответ 7

ps - самый надежный метод. Экран SHELL не может быть установлен, и даже если он есть, его можно легко подделать

Ответ 8

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

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

Ответ 9

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

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

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

ОБНОВЛЕНИЕ: как указал Тоби Спейт, это был бы более правильный и более чистый способ достижения того же самого:

basename $(readlink /proc/$$/exe)

Ответ 10

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

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.

Ответ 11

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

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

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

Ответ 12

Если ваш /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}'

Ответ 14

Ни один из ответов не работал с оболочкой 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.: (

Ответ 15

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

Прямо вперед

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

Хакский подход

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

Ответ 16

В Mac OS X (& FreeBSD):

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

Ответ 17

Если вы просто хотите проверить, что вы работаете (конкретная версия) 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 будут совместимы.

Ответ 18

Grepping PID с выхода "ps" не требуется, потому что вы можете прочитать соответствующую командную строку для любой структуры каталога PID из /proc:

echo $(cat /proc/$$/cmdline)

Однако это может быть не лучше, чем просто:

echo $0

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

<some_shell> --version

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

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

Ответ 19

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

Я понимаю, что ответ немного поздний в этом добром старом 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-подобных оболочек.

Ответ 20

Мое решение:

ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1

Это должно быть переносимо для разных платформ и оболочек. Он использует ps как другие решения, но не полагается на sed или awk и отфильтровывает мусор из трубопровода и ps сам, поэтому оболочка всегда должна быть последней записью. Таким образом, нам не нужно полагаться на непереносимые переменные PID или выбирать правильные строки и столбцы.

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

Ответ 21

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

Ответ 22

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

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

Ответ 23

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

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

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

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