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


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

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

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

23 493

23 ответа:

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

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

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

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

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

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

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


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

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

    • $BASH на Баш

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

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

    • КШ имеет $PS3 и $PS4 set, тогда как обычный Bourne shell (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, то в том же терминале, попасть в какой-то другой оболочки(КШ например) и попробовать $SHELL, вы увидите результат как баш в обоих случаях.

чтобы получить имя текущей оболочки, используйте 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.) Для /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 $$

Он также работает под программа и не может производить ложные срабатывания как PID grepping. При некоторой очистке он выводит только имя исполняемого файла (под программа С пути):

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.

from 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 оболочка (она не имеет переменных $$ или ).

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

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

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

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

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

сделайте следующее, чтобы узнать, использует ли ваша оболочка DASH/BASH.

1) ls-la / bin / sh, если результат / bin / sh - > / bin / bash ==> тогда ваша оболочка использует BASH.

Если результат / bin / sh - > / bin / 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}'