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