Как определить текущую оболочку, над которой я работаю?
Как определить текущую оболочку, над которой я работаю?
будет выводить 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и$PS4set, тогда как нормальная оболочка Борна (sh) только$PS1и$PS2set. Это вообще кажется самым трудным отличить - единственная разница во всем наборе переменных окружающей среды между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}'