Тестирование определенных возможностей (например, выполняет ли !подстановка?), Вероятно, более переносимо, чем поиск имени оболочки. По местным обычаям вы можете запускать что-то по имени, /bin/shкоторое на самом деле может быть ash, dash, bash и т. Д.
msw,
1
@msw: похоже на хороший комментарий, но это заставляет меня задуматься: «Как?».
Нобар
Похоже, что нет простого ответа на этот вопрос. Если мы не можем запросить оболочку, возможно, лучший подход - всегда указывать оболочку. Я не уверен, что это всегда возможно, но, возможно, это легче сделать, чем обычно думают люди.
@Aniket, не так много помощи, как вы думаете - это интересует только интерактивные процессы оболочки.
Тоби Спейт
Ответы:
794
Есть три подхода к поиску имени исполняемого файла текущей оболочки:
Обратите внимание, что все три подхода могут быть обмануты, если исполняемый файл оболочки есть /bin/sh, но он действительно переименованbash , например (что часто случается).
Таким образом, на ваш второй вопрос о том, psподойдет ли вывод, ответ « не всегда ».
echo $0 - напечатает имя программы ... которая в случае оболочки является реальной оболочкой.
ps -ef | grep $$ | grep -v grep- это будет искать текущий идентификатор процесса в списке запущенных процессов. Поскольку текущий процесс является оболочкой, он будет включен.
Это не на 100% надежно, так как у вас могут быть другие процессы, чей psсписок содержит то же число, что и идентификатор процесса оболочки, особенно если этот идентификатор является небольшим числом (например, если PID оболочки равен «5», вы можете найти процессы, называемые "java5" или "perl5" в том же grepвыводе!). Это вторая проблема с подходом "ps", из-за невозможности полагаться на имя оболочки.
echo $SHELL- Путь к текущей оболочке сохраняется как SHELLпеременная для любой оболочки. Предостережение для этого заключается в том, что если вы явно запустите оболочку как подпроцесс (например, это не ваша оболочка входа в систему), вы получите вместо этого значение вашей оболочки входа в систему. Если это возможно, используйте psили $0подход.
Однако, если исполняемый файл не соответствует вашей фактической оболочке (например, /bin/shна самом деле bash или ksh), вам нужна эвристика. Вот некоторые переменные среды, специфичные для различных оболочек:
$version установлен на tcsh
$BASH установлен на баш
$shell (в нижнем регистре) устанавливается фактическое имя оболочки в csh или tcsh
$ZSH_NAME установлен на зш
ksh имеет $PS3и $PS4установил, тогда как нормальная оболочка Bourne ( sh) только имеет $PS1и $PS2установил. Как правило , это кажется , что труднее всего отличить - на только разницу во всей совокупности переменной среды между shи kshмы установили на Solaris Boxen является $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, и $TMOUT.
ps -p $$как указывает Мэтью Слэттери . Для ksh: echo $KSH_VERSIONили echo ${.sh.version}.
Приостановлено до дальнейшего уведомления.
@Dennish - мой ksh сейчас не имеет установленного KSH_VERSION. и echo ${.sh.version}возвращает «Bad Substitution». Смотрите мое решение выше
ДВК
3
« ps -ef | grep …… Это не на 100% надежно, как…» Использование простого регулярного выражения с помощью egrepили grep -eможет легко довести надежность до 100%: для всех целей ps -ef | egrep "^\s*\d+\s+$$\s+". Он ^гарантирует, что мы начинаем с начала строки, \d+потребляет UID, $$совпадает с PID, а также \s*и \s+учитывают и обеспечивают пробел между другими частями.
Слипп Д. Томпсон
2
@ SlippD. Томпсон не работал в GNU / Linux. Но это похоже на работу:ps -ef | awk '$2==pid' pid=$$
Ярно
98
ps -p $$
должен работать везде, где задействованы ps -efи grepработают решения (в любом варианте Unix, который поддерживает параметры POSIXps ), и не будет страдать от ложных срабатываний, вызванных поиском последовательности цифр, которая может появиться в другом месте.
Некоторые оболочки имеют свои собственные встроенные версии, psкоторые могут не понимать, -pпоэтому вам может потребоваться использовать /bin/ps -p $$.
Приостановлено до дальнейшего уведомления.
13
Все снаряды, с которыми я знаком, понимают, $$за исключением того, fishчто вам придется использовать ps -p %self.
Приостановлено до дальнейшего уведомления.
3
На самом деле, вы не должны полагаться на сложные пути, такие как /bin/ps. psможет быть легко (на самом деле это вполне нормально в настоящее время) может быть установлен в /usr/bin. $(which ps) -p $$это лучший способ. Конечно, это не будет работать в рыбе и, возможно, в некоторых других оболочках. Я думаю, что это (which ps) -p %selfв рыбе.
Арон Седерхольм,
1
В некоторых минимальных системах, таких как докерский контейнер debian-slim, ps может и не быть. В этом случае этот подход все еще работает:readlink /proc/$$/exe
mxmlnkn
если ваш shэмулируется bash, ps -p даст вам, /usr/bin/bashдаже если вы запустите его какsh
Это хороший короткий. Я использовал себя ps -o fname --no-headers $$.
Анн ван Россум
Спасибо. Я обнаружил, что это лучший вариант для использования в скрипте для защиты определенных команд bash test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash. (Следующая строка в моем скрипте имеет эквивалент для csh.)
craq
1
Я обнаружил, что если вы делаете это изнутри, то это может привести к ложным дополнительным строкам путем сопоставления PID родителя и фактического процесса оболочки. Для этого я использую -qвместо -p:SHELL=$(ps -ocomm= -q $$)
Стив
35
Если вы просто хотите убедиться, что пользователь вызывает скрипт с Bash:
if[!-n "$BASH"];then echo Please run this script $0 with bash;exit1;fi
Это не должно быть ближе к вершине, потому что это не отвечает на вопрос вообще. Если вопрос будет «Как проверить, работает ли скрипт под Bash», я голосую за него.
Дэвид Ференци Рогожан,
2
@DawidFerenczy - этот вопрос является лучшим результатом при поиске этой фразы. В конечном счете, я думаю, что гораздо важнее, чтобы ответы отвечали на то, что ищут люди, а не на то, о чем был первоначальный вопрос.
ArtOfWarfare
3
Кроме того, переменный $ BASH будет определен в Tcsh , если Tcsh вызывается из Баша
+18446744073709551615
Это очень полезно, спасибо. Просто адаптировать его немного, поставив его в качестве второй линии после того, как #!/bin/bash: if [ ! -n "$BASH" ] ;then exec bash $0; fi. С этой строкой скрипт запускается с использованием bash, даже если он запускается с использованием ksh или sh. Мой вариант использования не нуждается в аргументах командной строки, но они могут быть добавлены после, $0если это необходимо.
Какой смысл в grep, за которым следует awk, когда это /pattern/ { action }будет сделано?
Йенс
# в zshell alias shell = 'echo $ {SHELL: t}'
SergioAraujo
4
$SHELLПеременная окружения содержит оболочку, которая настроена по умолчанию для текущего пользователя. Он не отражает оболочку, которая в данный момент работает. Также лучше использовать, ps -p $$чем grepping $$ из-за ложных срабатываний.
Дэвид Ференци Рогожан,
$ SHELL env. переменная указывает на «родительскую» оболочку, как указано в спецификации POSIX: SHELL Эта переменная должна представлять путь к предпочтительному интерпретатору языка команд пользователя. Поэтому значение $ SHELL может не быть текущей оболочкой.
Тео
все внутри awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
go2null
16
$SHELLне всегда нужно показывать текущую оболочку. Он отражает только оболочку по умолчанию, которая будет вызвана.
Чтобы проверить вышесказанное, скажем, bashэто оболочка по умолчанию, попробуйте echo $SHELL, а затем в том же терминале перейдите в другую оболочку (например, KornShell (ksh)) и попробуйте $SHELL. Вы увидите результат как bash в обоих случаях.
Чтобы получить имя текущей оболочки, используйте cat /proc/$$/cmdline. И путь к исполняемому файлу оболочки readlink /proc/$$/exe.
+1 $ SHELL - оболочка по умолчанию для программ, которые должны ее породить. Это не обязательно отражает оболочку, которая в данный момент работает.
Джим Льюис
8
У меня есть простой трюк, чтобы найти текущую оболочку. Просто введите случайную строку (которая не является командой). Он потерпит неудачу и вернет ошибку «not found», но в начале строки скажет, какая это оболочка:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Ничего хорошего в сценарии. echo 'aaaa' > script; chmod +x script; ./scriptдает./script.sh: 1: aaaa: not found
стройная
6
Далее всегда будет указана фактическая используемая оболочка - она получает имя фактического исполняемого файла, а не имя оболочки (т.е. ksh93вместо kshи т. Д.). Для /bin/sh, он покажет реальную оболочку используется, то есть dash.
ls -l /proc/$$/exe | sed 's%.*/%%'
Я знаю, что многие говорят, что lsвывод никогда не должен обрабатываться, но какова вероятность того, что у вас будет оболочка, которую вы используете, которая названа со специальными символами или помещена в каталог со специальными символами? Если это все еще так, есть много других примеров того, как сделать это по-другому.
Как указал Тоби Спейт , это было бы более правильным и более чистым способом достижения того же самого:
Это просто ошибки на всех Unices, которые не предоставляют /proc. Не все в мире Linux box.
Дженс
5
И если вы находитесь на Linux, мы бы предпочли , basename $(readlink /proc/$$/exe)чтобы ls+ sed+ echo.
Тоби Спейт
1
Это даст имя фактического исполняемого файла , а не фактической оболочки . Когда фактическая оболочка связана как апплет busybox, скажем ash -> /bin/busybox, это даст / bin / busybox.
stepse
6
Я перепробовал много разных подходов, и лучший для меня:
ps -p $$
Это также работает под Cygwin и не может выдавать ложные срабатывания в качестве подсказки ПИД-регулятора. С некоторой очисткой он выводит только имя исполняемого файла (под Cygwin с путем):
ps -p $$ | tail -1| awk '{print $NF}'
Вы можете создать функцию, чтобы вам не пришлось ее запоминать:
# Print currently active shell
shell (){
ps -p $$ | tail -1| awk '{print $NF}'}
На мой взгляд (Cygwin | Windows 7) ваш ответ самый лучший, и ps -p $$ | хвост -1 | gawk '{print $ NF}' работает даже из cmd без $ bash. Обратите внимание на gawk вместо awk, так как awk работает только из bash.
WebComer
@WebComer Извините, я не уверен, что вы подразумеваете под " работает даже из cmd без $ bash ". Даже если у вас есть порты Windows ps, tailи gawk, cmd не определяет $$как его PID, поэтому он определенно не может работать под простым cmd.
Дэвид Ференци Рогожан
Почему не просто ps -p$$ -o comm=? POSIX говорит, что указание всех пустых заголовков полностью подавляет заголовок. Мы по-прежнему терпим неудачу (как и все psответы), когда мы получаем непосредственно исполняемый скрипт (например #!/bin/sh).
Тоби Спейт
5
Мой вариант по распечатке родительского процесса:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Не запускайте ненужные приложения, когда AWK может сделать это за вас.
Зачем запускать ненужное awk, когда ps -p "$$" -o 'comm='можешь сделать это за тебя?
Тоби Спейт
5
Существует много способов узнать оболочку и соответствующую ей версию. Вот несколько, которые работали для меня.
прямой
$> echo $ 0 (Дает вам имя программы. В моем случае вывод был -bash .)
$> $ SHELL (Это приведет вас в оболочку, и в командной строке вы получите имя и версию оболочки. В моем случае bash3.2 $ .)
$> echo $ SHELL (Это даст вам исполняемый путь. В моем случае / bin / bash .)
$> $ SHELL --version (Это даст полную информацию о программном обеспечении оболочки с типом лицензии)
Хакерский подход
$> ******* (введите набор случайных символов, и в выходных данных вы получите имя оболочки. В моем случае -bash: chapter2-a-sample-isomorphic-app: команда не найдена )
При условии, что вы /bin/shподдерживаете стандарт POSIX и в вашей системе установлена lsofкоманда - возможной альтернативой lsofможет быть в этом случае pid2path- вы также можете использовать (или адаптировать) следующий скрипт, который печатает полные пути:
#!/bin/sh# cat /usr/local/bin/curshset-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";exit1;}export PATH
cmd="lsof"
env -i PATH="${PATH}" type "$cmd"1>/dev/null2>&1||{ echo "$cmd not found";exit1;}
awkstr="`echo "$@" | 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";exit1;}
lsofstr="`lsof -p $ppid`"||{ printf "%s\n""lsof failed""try: sudo lsof -p \`ps -p \$\$ -o ppid=\`";exit1;}
printf "%s\n""${lsofstr}"|
LC_ALL=C awk -v var="${awkstr}"'$NF ~ var {print $NF}'
это работает в рыбе! но для меня в bash происходит сбой из-за -iопции (-> ignore environment) envв строке, где вы проверяете lsofдоступность. это терпит неудачу с: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
hoijui
2
Если вы просто хотите проверить, что вы используете (конкретную версию) 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 arraysif!eval"declare -A _ARRAY && func-name() { :; }"2>/dev/null;then
echo >&2"bash $BASH_VERSION is not supported (not really bash?)"exit1fi;;*/bash@[123])
echo >&2"bash $BASH_VERSION is not supported (version 4+ required)"exit1;;*)
echo >&2"This script requires BASH (version 4+) - not regular sh"
echo >&2"Re-run as \"bash $CMD\" for proper operation"exit1;;esac
В первом случае вы могли бы опустить несколько параноидальную функциональную проверку функций и просто предположить, что будущие версии Bash будут совместимы.
Ни один из ответов не работал с 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 extesions, попробуйте добавить , --posixчтобы проверить его). Все они являются стандартными командами POSIX. Я уверен, что tailможет быть удален, но мой sedфу не достаточно силен, чтобы сделать это.
Мне кажется, что это решение не очень переносимо, так как не работает на OS X. :(
Это должно быть переносимо на разные платформы и оболочки. Он использует , psкак и другие решения, но это не зависит от sedили awkи отфильтровывает мусор из трубопровода и psсами , так что оболочка должна всегда быть последним. Таким образом, нам не нужно полагаться на непереносимые переменные PID или выбирать правильные строки и столбцы.
Я тестировал на Debian и macOS с Bash, Z shell ( zsh) и fish (который не работает с большинством этих решений без изменения выражения специально для fish, потому что он использует другую переменную PID).
Попробовал это при использовании zsh, и это дало мне -bash.
user137369
В моей системе (сейчас), протестированной с bash и dash, это возвращение mutt...: -b
Ф. Хаури
1
Подбирать PID из вывода «ps» не нужно, потому что вы можете прочитать соответствующую командную строку для любого PID из структуры каталогов / proc:
echo $(cat /proc/$$/cmdline)
Однако это может быть не лучше, чем просто:
echo $0
Что касается запуска фактически другой оболочки, чем указано в названии, одна идея состоит в том, чтобы запросить версию из оболочки, используя имя, которое вы получили ранее:
<some_shell> --version
sh Кажется, что с ошибкой код выхода 2, в то время как другие дают что-то полезное (но я не могу проверить все, так как у меня их нет):
Это не очень чистое решение, но оно делает то, что вы хотите.
# MUST BE SOURCED..
getshell(){local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"
shells_array=(# It is important that the shells are listed in descending order of their name length.
pdksh
bash dash mksh
zsh ksh
sh
)local suited=falsefor i in ${shells_array[*]};doif![-z `printf $shell | grep $i`]&&! $suited;then
shell=$i
suited=truefidone
echo $shell
}
getshell
Теперь вы можете использовать $(getshell) --version .
Это работает, однако, только на KornShell- подобных оболочках (ksh).
«Это работает, однако, только на ksh-подобных оболочках». Вы говорите, что я должен проверить оболочку перед запуском этого? Хм ...
jpaugh
@jpaugh, списки должны быть поддержаны оболочки Sourcing этот код, который не относится к dash, и yashт.д. Как правило, если вы используете bash, zsh, ksh, что угодно , - вы не должны заботиться о таких вещах.
theoden8
То есть вы считаете bash "кш-подобным"? Понял. Это имеет больше смысла
jpaugh
@ jpaugh, ну вот что я имел ввиду ksh набор функций - это в основном подмножество bashфункций (хотя я не проверил это полностью).
theoden8
1
Чтобы узнать, использует ли ваша оболочка Dash / Bash, выполните следующие действия.
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 и повторите попытку.
Во-первых, это чепуха, echo $SHELLделай то, что ты пытаешься делать, и делай это хорошо. Второй также не годится, потому что $SHELLпеременная окружения содержит оболочку по умолчанию для текущего пользователя, а не работающую в данный момент оболочку. Если я, например, bashустановил в качестве оболочки по умолчанию, выполнить zshи echo $SHELL, он напечатает bash.
Дэвид Ференци Рогожан,
Вы правы, Давид Ференчи. Мы можем использовать команду ps для определения текущей оболочки. [# ps -p $$ | хвост -1 | awk '{print $ 4}'].
!
подстановка?), Вероятно, более переносимо, чем поиск имени оболочки. По местным обычаям вы можете запускать что-то по имени,/bin/sh
которое на самом деле может быть ash, dash, bash и т. Д.Ответы:
Есть три подхода к поиску имени исполняемого файла текущей оболочки:
Обратите внимание, что все три подхода могут быть обмануты, если исполняемый файл оболочки есть
/bin/sh
, но он действительно переименованbash
, например (что часто случается).Таким образом, на ваш второй вопрос о том,
ps
подойдет ли вывод, ответ « не всегда ».echo $0
- напечатает имя программы ... которая в случае оболочки является реальной оболочкой.ps -ef | grep $$ | grep -v grep
- это будет искать текущий идентификатор процесса в списке запущенных процессов. Поскольку текущий процесс является оболочкой, он будет включен.Это не на 100% надежно, так как у вас могут быть другие процессы, чей
ps
список содержит то же число, что и идентификатор процесса оболочки, особенно если этот идентификатор является небольшим числом (например, если PID оболочки равен «5», вы можете найти процессы, называемые "java5" или "perl5" в том жеgrep
выводе!). Это вторая проблема с подходом "ps", из-за невозможности полагаться на имя оболочки.echo $SHELL
- Путь к текущей оболочке сохраняется какSHELL
переменная для любой оболочки. Предостережение для этого заключается в том, что если вы явно запустите оболочку как подпроцесс (например, это не ваша оболочка входа в систему), вы получите вместо этого значение вашей оболочки входа в систему. Если это возможно, используйтеps
или$0
подход.Однако, если исполняемый файл не соответствует вашей фактической оболочке (например,
/bin/sh
на самом деле bash или ksh), вам нужна эвристика. Вот некоторые переменные среды, специфичные для различных оболочек:$version
установлен на tcsh$BASH
установлен на баш$shell
(в нижнем регистре) устанавливается фактическое имя оболочки в csh или tcsh$ZSH_NAME
установлен на зшksh имеет
$PS3
и$PS4
установил, тогда как нормальная оболочка Bourne (sh
) только имеет$PS1
и$PS2
установил. Как правило , это кажется , что труднее всего отличить - на только разницу во всей совокупности переменной среды междуsh
иksh
мы установили на Solaris Boxen является$ERRNO
,$FCEDIT
,$LINENO
,$PPID
,$PS3
,$PS4
,$RANDOM
,$SECONDS
, и$TMOUT
.источник
ps -p $$
как указывает Мэтью Слэттери . Дляksh
:echo $KSH_VERSION
илиecho ${.sh.version}
.echo ${.sh.version}
возвращает «Bad Substitution». Смотрите мое решение вышеps -ef | grep …
… Это не на 100% надежно, как…» Использование простого регулярного выражения с помощьюegrep
илиgrep -e
может легко довести надежность до 100%: для всех целейps -ef | egrep "^\s*\d+\s+$$\s+"
. Он^
гарантирует, что мы начинаем с начала строки,\d+
потребляет UID,$$
совпадает с PID, а также\s*
и\s+
учитывают и обеспечивают пробел между другими частями.ps -ef | awk '$2==pid' pid=$$
ps -p $$
должен работать везде, где задействованы
ps -ef
иgrep
работают решения (в любом варианте Unix, который поддерживает параметры POSIXps
), и не будет страдать от ложных срабатываний, вызванных поиском последовательности цифр, которая может появиться в другом месте.источник
ps
которые могут не понимать,-p
поэтому вам может потребоваться использовать/bin/ps -p $$
.$$
за исключением того,fish
что вам придется использоватьps -p %self
./bin/ps
.ps
может быть легко (на самом деле это вполне нормально в настоящее время) может быть установлен в/usr/bin
.$(which ps) -p $$
это лучший способ. Конечно, это не будет работать в рыбе и, возможно, в некоторых других оболочках. Я думаю, что это(which ps) -p %self
в рыбе.readlink /proc/$$/exe
sh
эмулируетсяbash
, ps -p даст вам,/usr/bin/bash
даже если вы запустите его какsh
Пытаться
или
источник
ps -o fname --no-headers $$
.test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash
. (Следующая строка в моем скрипте имеет эквивалент для csh.)-q
вместо-p
:SHELL=$(ps -ocomm= -q $$)
Если вы просто хотите убедиться, что пользователь вызывает скрипт с Bash:
источник
#!/bin/bash
:if [ ! -n "$BASH" ] ;then exec bash $0; fi
. С этой строкой скрипт запускается с использованием bash, даже если он запускается с использованием ksh или sh. Мой вариант использования не нуждается в аргументах командной строки, но они могут быть добавлены после,$0
если это необходимо.Ты можешь попробовать:
Или:
источник
/pattern/ { action }
будет сделано?$SHELL
Переменная окружения содержит оболочку, которая настроена по умолчанию для текущего пользователя. Он не отражает оболочку, которая в данный момент работает. Также лучше использовать,ps -p $$
чем grepping $$ из-за ложных срабатываний.awk
,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELL
не всегда нужно показывать текущую оболочку. Он отражает только оболочку по умолчанию, которая будет вызвана.Чтобы проверить вышесказанное, скажем,
bash
это оболочка по умолчанию, попробуйтеecho $SHELL
, а затем в том же терминале перейдите в другую оболочку (например, KornShell (ksh)) и попробуйте$SHELL
. Вы увидите результат как bash в обоих случаях.Чтобы получить имя текущей оболочки, используйте
cat /proc/$$/cmdline
. И путь к исполняемому файлу оболочкиreadlink /proc/$$/exe
.источник
/proc
.PS это самый надежный метод. Не гарантируется, что переменная окружения SHELL будет установлена, и даже если она есть, она может быть легко подделана.
источник
У меня есть простой трюк, чтобы найти текущую оболочку. Просто введите случайную строку (которая не является командой). Он потерпит неудачу и вернет ошибку «not found», но в начале строки скажет, какая это оболочка:
источник
echo 'aaaa' > script; chmod +x script; ./script
дает./script.sh: 1: aaaa: not found
Далее всегда будет указана фактическая используемая оболочка - она получает имя фактического исполняемого файла, а не имя оболочки (т.е.
ksh93
вместоksh
и т. Д.). Для/bin/sh
, он покажет реальную оболочку используется, то естьdash
.Я знаю, что многие говорят, что
ls
вывод никогда не должен обрабатываться, но какова вероятность того, что у вас будет оболочка, которую вы используете, которая названа со специальными символами или помещена в каталог со специальными символами? Если это все еще так, есть много других примеров того, как сделать это по-другому.Как указал Тоби Спейт , это было бы более правильным и более чистым способом достижения того же самого:
источник
/proc
. Не все в мире Linux box.basename $(readlink /proc/$$/exe)
чтобыls
+sed
+echo
.ash -> /bin/busybox
, это даст / bin / busybox.Я перепробовал много разных подходов, и лучший для меня:
Это также работает под Cygwin и не может выдавать ложные срабатывания в качестве подсказки ПИД-регулятора. С некоторой очисткой он выводит только имя исполняемого файла (под Cygwin с путем):
Вы можете создать функцию, чтобы вам не пришлось ее запоминать:
... а затем просто выполнить
shell
.Он был протестирован под Debian и Cygwin.
источник
ps
,tail
иgawk
, cmd не определяет$$
как его PID, поэтому он определенно не может работать под простым cmd.ps -p$$ -o comm=
? POSIX говорит, что указание всех пустых заголовков полностью подавляет заголовок. Мы по-прежнему терпим неудачу (как и всеps
ответы), когда мы получаем непосредственно исполняемый скрипт (например#!/bin/sh
).Мой вариант по распечатке родительского процесса:
Не запускайте ненужные приложения, когда AWK может сделать это за вас.
источник
awk
, когдаps -p "$$" -o 'comm='
можешь сделать это за тебя?Существует много способов узнать оболочку и соответствующую ей версию. Вот несколько, которые работали для меня.
прямой
Хакерский подход
$> ******* (введите набор случайных символов, и в выходных данных вы получите имя оболочки. В моем случае -bash: chapter2-a-sample-isomorphic-app: команда не найдена )
источник
При условии, что вы
/bin/sh
поддерживаете стандарт POSIX и в вашей системе установленаlsof
команда - возможной альтернативойlsof
может быть в этом случаеpid2path
- вы также можете использовать (или адаптировать) следующий скрипт, который печатает полные пути:источник
-i
опции (-> ignore environment)env
в строке, где вы проверяетеlsof
доступность. это терпит неудачу с:env -i PATH="${PATH}" type lsof
->env: ‘type’: No such file or directory
Если вы просто хотите проверить, что вы используете (конкретную версию) Bash, лучший способ сделать это - использовать
$BASH_VERSINFO
переменную массива. Как переменная массива (только для чтения) ее нельзя установить в среде, поэтому вы можете быть уверены, что она поступает (если вообще) из текущей оболочки.Однако, поскольку Bash имеет другое поведение при вызове как
sh
, вам также необходимо проверить,$BASH
заканчивается ли переменная окружения/bash
.В написанном мной сценарии, который использует имена функций с
-
(не подчеркиванием) и зависит от ассоциативных массивов (добавлен в Bash 4), у меня есть следующая проверка работоспособности (с полезным сообщением об ошибке пользователя):В первом случае вы могли бы опустить несколько параноидальную функциональную проверку функций и просто предположить, что будущие версии Bash будут совместимы.
источник
Ни один из ответов не работал с
fish
оболочкой (она не имеет переменных$$
или$0
).Это работает для меня (проверено на
sh
,bash
,fish
,ksh
,csh
,true
,tcsh
, иzsh
; OpenSUSE 13.2):Эта команда выводит строку вроде
bash
. Здесь я только с помощьюps
,tail
иsed
(без GNU extesions, попробуйте добавить ,--posix
чтобы проверить его). Все они являются стандартными командами POSIX. Я уверен, чтоtail
может быть удален, но мойsed
фу не достаточно силен, чтобы сделать это.Мне кажется, что это решение не очень переносимо, так как не работает на OS X. :(
источник
sed: invalid option -- 'E'
на bash 3.2.51 и tcsh 6.15.00Мое решение:
Это должно быть переносимо на разные платформы и оболочки. Он использует ,
ps
как и другие решения, но это не зависит отsed
илиawk
и отфильтровывает мусор из трубопровода иps
сами , так что оболочка должна всегда быть последним. Таким образом, нам не нужно полагаться на непереносимые переменные PID или выбирать правильные строки и столбцы.Я тестировал на Debian и macOS с Bash, Z shell (
zsh
) и fish (который не работает с большинством этих решений без изменения выражения специально для fish, потому что он использует другую переменную PID).источник
Из Как вы знаете , что ваша текущая скорлупа? ,
источник
grep $$
ненадежно.ps -ef | awk -v pid=$$ '$2==pid { print $8 }'
лучше, но почему бы просто не использоватьps -p $$
?В Mac OS X (и FreeBSD):
источник
zsh
, и это дало мне-bash
.mutt
...: -bПодбирать PID из вывода «ps» не нужно, потому что вы можете прочитать соответствующую командную строку для любого PID из структуры каталогов / proc:
Однако это может быть не лучше, чем просто:
Что касается запуска фактически другой оболочки, чем указано в названии, одна идея состоит в том, чтобы запросить версию из оболочки, используя имя, которое вы получили ранее:
sh
Кажется, что с ошибкой код выхода 2, в то время как другие дают что-то полезное (но я не могу проверить все, так как у меня их нет):источник
Это не очень чистое решение, но оно делает то, что вы хотите.
Теперь вы можете использовать
$(getshell) --version
.Это работает, однако, только на KornShell- подобных оболочках (ksh).
источник
dash
, иyash
т.д. Как правило, если вы используетеbash
,zsh
,ksh
, что угодно , - вы не должны заботиться о таких вещах.ksh
набор функций - это в основном подмножествоbash
функций (хотя я не проверил это полностью).Чтобы узнать, использует ли ваша оболочка Dash / Bash, выполните следующие действия.
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 и повторите попытку.
источник
И я придумал это
источник
Пожалуйста, используйте следующую команду:
источник
echo $SHELL
делай то, что ты пытаешься делать, и делай это хорошо. Второй также не годится, потому что$SHELL
переменная окружения содержит оболочку по умолчанию для текущего пользователя, а не работающую в данный момент оболочку. Если я, например,bash
установил в качестве оболочки по умолчанию, выполнитьzsh
иecho $SHELL
, он напечатаетbash
.echo $SHELL
может быть мусором:~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Этот хорошо работает на Red Hat Linux (RHEL), macOS, BSD и некоторых AIX :
альтернативно, следующий также должен работать, если pstree доступен,
источник