it-roy-ru.com

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

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

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

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

555
josh
  • Существует три подхода к нахождению name текущего исполняемого файла Shell:

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

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

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

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

      Это не на 100% надежно, так как у вас могут быть ДРУГИЕ процессы, чей список ps содержит тот же номер, что и идентификатор процесса Shell, особенно если этот идентификатор является маленьким # (например, если PID Shell равен "5", вы можете найти процессы с именем "Java5"). "или" Perl5 "в том же выводе grep!). Это вторая проблема с подходом "ps", из-за невозможности полагаться на имя Shell.

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


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

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

    • $BASH установлен на bash

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

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

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

708
DVK

ps -p $$

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

86
Matthew Slattery

Пытаться

ps -p $$ -oargs=

или же

ps -p $$ -ocomm=
35
Nahuel Fouilleul

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

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

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

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

Или же:

echo $Shell
19
karlphillip

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

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

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

11
sr01853

pS самый надежный метод. Shell envar не гарантируется, и даже если он установлен, его можно легко подделать

9
ennuikiller

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

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

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

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

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

7
vadimbog

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

ps -p $$

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

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

Вы можете создать функцию, чтобы вам не пришлось ее запоминать:

# print currently active Shell
shell () {
  ps -p $$ | tail -1 | awk '{print $NF}'
}

... а затем просто выполните Shell.

Протестировано под Debian и Cygwin.

4
Dawid Ferenczy Rogožan

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

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

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

4
Matthew Stier

При условии, что ваш /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 "[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}'
3
carlo
echo $$ # Gives the Parent Process ID 
ps -ef | grep $$ | awk '{print $8}' #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

2
Moisei

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

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

1
theoden

В Mac OS X (и FreeBSD):

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

Мое решение:

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

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

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

1
wickles

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

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

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

echo $0

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

<some_Shell> --version

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

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

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

ПРИМЕЧАНИЕ. Если приведенная выше команда выдает сообщение об ошибке:/bin/sh уже существует, удалите/bin/sh и повторите попытку.

1
Shiva

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

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

1
Alex Dupuy

Ни один из ответов не работал с оболочкой 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; попробуйте добавить --posix, чтобы проверить это). Все они являются стандартными командами POSIX. Я уверен, что tail можно удалить, но мой sed не достаточно силен, чтобы сделать это.

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

1
rominf

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

прямо

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

хакерский подход

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

1
Devang Paliwal

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

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