Как определить текущую оболочку, над которой я работаю?
Как я могу определить текущую оболочку, над которой я работаю?
будет вывод 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и$PS4set, тогда как обычный Bourne shell (sh) только$PS1и$PS2set. Это вообще кажется самым трудным отличить-единственная разница во всем наборе экологических переменных междуshиkshмы установили на Solaris Боксен-это$ERRNO,$FCEDIT,$LINENO,$PPID,$PS3,$PS4,$RANDOM,$SECONDS,$TMOUT.
ps -p $$должен работать в любом месте, что решения с участием
ps -efиgrepdo (на любом варианте 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вместоkshetc.) Для/bin/shпокажет фактическую оболочку используется: т. е.dashls -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> --versionsh, похоже, не работает с кодом выхода 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 и повторите попытку.