Как определить текущую оболочку, над которой я работаю?
Как я могу определить текущую оболочку, над которой я работаю?
будет вывод ps
достаточно одной команды?
Как это можно сделать в разных вариантах UNIX?
23 ответа:
есть 3 подхода к нахождению имя исполняемого файла текущей оболочки:
обратите внимание, что все 3 подхода можно обмануть, если исполняемый файл оболочки
/bin/sh
но это действительно переименованbash
, например (что часто бывает).таким образом ваш второй вопрос о том,
ps
выход будет делать ответ с "не всегда".
echo
- выведет имя программы... который в случае shell является фактическим shell
ps -ef | grep $$ | grep -v grep
- это будет искать текущий идентификатор процесса в списке запущенных процессов. Поскольку текущий процесс является оболочкой, он будет включен.это не на 100% надежно, так как у вас могут быть другие процессы, чьи
ps
список включает в себя тот же номер, что и идентификатор процесса оболочки, особенно если этот идентификатор небольшой # (например, если PID оболочки "5", Вы можете найти процессы, называемые" java5 "или" perl5 " в том жеgrep
выход!). Это вторая проблема с подходом "ps", Помимо невозможности полагаться на имя оболочки.
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 для последовательности цифр, которые могут появиться в другом месте.
Если вы просто хотите убедиться, что пользователь вызывает скрипт с 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.
если вы просто хотите проверить, что вы работаете (конкретная версия) 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).
есть много способов узнать оболочку и ее соответствующую версию. Вот несколько, которые работали на меня.
вперед
- $>echo $0 (дает вам имя программы. В моем случае выход был Баш)
- $> $SHELL (это приведет вас в оболочку и в приглашении вы получите имя оболочки и версию. В моем случае bash3.2$)
- $> echo $SHELL (это даст вам путь к исполняемому файлу. В моем случае / bin / bash)
- $> $SHELL -- version (это даст полную информацию о программном обеспечении оболочки с типом лицензии)
подход программистские
$> ******* (введите набор случайных символов и на выходе вы получите имя оболочки. В моем случае - bash: chapter2-a-sample-isomorphic-app: command not нашел)
сделайте следующее, чтобы узнать, использует ли ваша оболочка 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 и повторите попытку.