определить оболочку в скрипте во время выполнения

22

Насколько мне известно, для определения текущей оболочки мы используем echo $0в оболочке. Скорее я хочу, чтобы мой скрипт проверял, в какой оболочке он работает. Итак, я попытался напечатать $0в сценарии, и он возвращает имя сценария, как и должно. Итак, мой вопрос: как я могу определить, в какой оболочке работает мой скрипт во время выполнения?

g4ur4v
источник
какой язык сценариев вы используете? Кроме того, в худшем случае вы всегда можете выложить системную команду, чтобы получить результаты «echo $ 0» внутри скрипта.
BriGuy
echo $0здесь не вариант, так как скрипт будет работать на разных машинах, где первое, что мне нужно проверить, это оболочка.
g4ur4v
Так что же такое язык сценариев?
BriGuy
@BriGuy: это скрипт оболочки Unix.
g4ur4v
3
Ну, если вы добавите #! /bin/sh -сверху, он будет работать sh. Вы имеете в виду, что это за вариант sh?
Стефан Шазелас

Ответы:

28

На Linux вы можете использовать /proc/PID/exe.

Пример:

# readlink /proc/$$/exe
/bin/zsh
Патрик
источник
3
Это слишком специфично для меня (например, в Debian он печатает zsh4 или ksh93). /bin/sed -r -e 's/\x0.*//' /proc/$$/cmdlineвместо этого выдает zsh или ksh. (Это было бы $ 0, если оболочка волшебным образом не исправила это, чтобы вместо этого дать имя сценариям).
frostschutz
@frostschutz Твой лучший ответ, беги за +500!
Тереза ​​и Джуниор
5
Это страдает от страшного всего мира Linux Box болезнь. /procнастолько же уродлив и непереносим, ​​насколько это возможно.
Йенс,
7
@Jens, поэтому я указал, что это относится только к Linux. /procне «некрасиво». /procчасто очень элегантное решение. Непереносимый да, но потому, что что-то непереносимо, не делает его уродливым.
Патрик
3
@ Патрик Я считаю /procуродливым, потому что файлы в нем могут приходить и уходить по прихоти разработчиков, а содержимое файлов может изменяться без предварительного уведомления, вызывая бесконечные боли из-за битрота и перемещения целевых форматов файлов.
Дженс
48

Может быть, не то, что вы просите, но это должно работать до некоторой степени, чтобы идентифицировать переводчика, который в настоящее время интерпретирует его для таких как Томпсон (ош), Борн, Борн-снова (баш), Корн (ksh88, ksh93, pdksh, mksh ), zsh, совместимый с политикой обычный (шикарный), еще один (yash), rc, akanga, es shell, wish, tclsh, ожидаемый, perl, python, ruby, php, JavaScript (по крайней мере, nodejs, оболочка SpiderMonkey и JSPL) , MS / Wine cmd.exe, command.com (MSDOS, FreeDOS ...).

'echo' +"'[{<?php echo chr(13)?>php <?php echo PHP_VERSION.chr(10);exit;?>}\
@GOTO DOS [exit[set 1 [[set 2 package] names];set 3 Tcl\ [info patchlevel];\
if {[lsearch -exact $1 Expect]>=0} {puts expect\ [$2 require Expect]\ ($3)} \
elseif {[lsearch -exact $1 Tk]>=0} {puts wish\ ($3,\ Tk\ [$2 require Tk])} \
else {puts $3}]]]' >/dev/null ' {\">/dev/null \
">"/dev/null" +"\'";q="#{",1//2,"}";a=+1;q='''=.q,';q=%{\"
'echo' /*>/dev/null
echo ">/dev/null;status=0;@ {status=1};*=(" '$' ");~ $status 1&&{e='"\
"';eval catch $2 ^'&version {eval ''echo <='^ $2 ^'&version''}';exit};e='"\
"';if (eval '{let ''a^~a''} >[2] /dev/null'){e='"\
"';exec echo akanga};eval exec echo rc $2 ^ version;\" > /dev/null
: #;echo possibly pre-Bourne UNIX V1-6 shell;exit
if (! $?version) set version=csh;exec echo $version
:DOS
@CLS
@IF NOT "%DOSEMU_VERSION%"=="" ECHO DOSEMU %DOSEMU_VERSION%
@ECHO %OS% %COMSPEC%
@VER
@GOTO FIN
", unless eval 'printf "perl %vd\n",$^V;exit;'> "/dev/null";eval ': "\'';
=S"';f=false e=exec\ echo n=/dev/null v=SH_VERSION;`(eval "f() { echo :
};f")2>$n` $f||$e Bourne-like shell without function
case `(: ${_z_?1}) 2>&1` in 1) $e ash/BSD sh;;esac;t(){
eval "\${$1$v+:} $f &&exec echo ${2}sh \$$1$v";};t BA ba;t Z z;t PO po;t YA ya
case `(typeset -Z2 b=0;$e $b)2>$n` in 00) (eval ':${.}')2>$n&&eval '
$e ksh93 ${.sh.version}';t K pdk;$e ksh88;;esac;case `(eval '$e ${f#*s}$($e 1
)$((1+1))')2>$n` in e12)$e POSIX shell;;esac;$e Bourne-like shell;: }
print "ruby ",RUBY_VERSION,"\n";exit;' ''';import sys
print("python "+sys.version);z='''*/;
s="";j="JavaScript";if(typeof process=="object"){p=console.log;p(process.title
,process.version)}else{p=print;p((f="function")==(t=typeof version)?"string"==
typeof(v=version())?v:(typeof build!=f?"":s= "SpiderMonkey ")+j+" "+v:(t==
"undefined"?j+"?":version)+"\n");if(s)build()}/*
:FIN } *///'''

Я опубликовал первоначальную версию сценария which_interpreter примерно в 2004 году в сети Usenet. У Sven Mascheck есть (возможно, более полезный для вас) скрипт, называемый whatshell, который фокусируется на идентификации оболочек типа Bourne. Вы также можете найти слитую версию наших двух сценариев там .

Стефан Шазелас
источник
3
Это не может идентифицировать Python 3, только Python 2. Чтобы это исправить, измените printего на функцию.
Крис Даун
39
На данный момент это самый большой момент в году. +1 за переносимость прошлого здравомыслия.
10
1
Было бы неплохо, если бы он узнал раковину рыбы.
Конрад Боровски
2
@xfix, я помню, что пытался еще до добавления php и javascript, но тогда не мог найти решение. Сложность возрастает экспоненциально с количеством поддерживаемых языков (поскольку все, что вы добавляете, должно быть действительным (или, по крайней мере, иметь незаметные побочные эффекты) во всех поддерживаемых языках), так что теперь это будет еще сложнее. Я не говорю, что это невозможно, но это, вероятно, означало бы отказ от поддержки некоторых других языков.
Стефан Шазелас
4
@iconoclast, поэтому он правильно определяет, bash 3.2.53(1)-releaseчто интерпретатор интерпретирует его.
Стефан Шазелас
12

Это то, что я использую в своем .profile для проверки наличия различных оболочек в системах, над которыми я работаю. Он не делает четких различий между ksh88 и ksh93, но никогда не подводил меня.

Обратите внимание, что не требуется ни одной вилки или трубы.

# Determine what (Bourne compatible) shell we are running under. Put the result
# in $PROFILE_SHELL (not $SHELL) so further code can depend on the shell type.

if test -n "$ZSH_VERSION"; then
  PROFILE_SHELL=zsh
elif test -n "$BASH_VERSION"; then
  PROFILE_SHELL=bash
elif test -n "$KSH_VERSION"; then
  PROFILE_SHELL=ksh
elif test -n "$FCEDIT"; then
  PROFILE_SHELL=ksh
elif test -n "$PS3"; then
  PROFILE_SHELL=unknown
else
  PROFILE_SHELL=sh
fi
Jens
источник
1
Обратите внимание, что только самые последние версии ksh93имеют $KSH_VERSION. Эта переменная пришла pdkshи не попала в AT & T ksh88.
Стефан Шазелас
Да, именно поэтому у меня есть второй тест для FCEDIT.
Дженс
1
Правильно. Обратите внимание, что posh(pdksh с большинством не-POSIX-функций удален, так что вы, вероятно, захотите назвать его «sh») не имеет ни FCEDIT, ни KSH_VERSION, но имеет PS3 (возможно, не долго), хотя вряд ли он будет использоваться в качестве оболочки для входа в систему , Также обратите внимание, что приведенный выше код не будет отражать, находится bashили zshнет shрежим эмуляции, что может быть проблемой, если вы используете, $PROFILE_SHELLчтобы решить, следует ли включить ту или иную функцию. Смотрите также Whatshell от Sven Mascheck, чтобы узнать, что вы можете (а можете и не захотеть) проверить.
Стефан Шазелас
6

Вы могли бы попробовать

ps -o args= -p "$$"

который даст вам имя команды, связанной с pid скрипта.

Flup
источник
Насколько я могу судить, не работает при использовании шебанга. sprunge.us/QeHD
Крис Даун
Извините, @ChrisDown, Flup. Мой плохой, я неправильно перевел cmdна commPOSIXifying ответ.
Стефан Шазелас
1

Если в lsofвашей системе есть команда, вы можете получить полный путь к исполняемому файлу родительской оболочки, получив родительский PID psи проанализировав результат lsof -p $ppid(см. Как определить текущую оболочку, над которой я работаю? ).

#!/bin/sh
ppid="`ps -p "$$" -o ppid=`"
lsof -nP -p "$ppid" | awk 'NR==3 {print $NF; exit}'
мари
источник
В моей системе это возвращает /, если я использую, NR==4я получаю путь к родителю оболочки.
Тор
Обратите внимание, что в POSIX shесть $PPIDпеременная. На Linux, вы можете использовать readlink -f "/proc/$PPID/exe".
Стефан Шазелас
1

Вне земли Linux или отсутствия доступа к файловой системе / proc или эквивалентной, вы можете использовать pstree:

Если у вас есть пид

На Mac:

./test.sh 
16012
-+= 00001 root /sbin/launchd
 \-+= 00245 wingwong /sbin/launchd
   \-+= 04670 wingwong /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal -psn_0_2052597
     \-+= 11816 root login -pf wingwong
       \-+= 11817 wingwong -bash
         \-+= 16012 wingwong ksh ./test.sh
           \-+- 16013 wingwong pstree -p 16012

На коробке Linux:

./test.sh 
14981
bash(14981)---pstree(14982)

Формат и стиль вывода из pstree различаются в зависимости от вашей среды, но вы можете включить вывод ASCII, а затем sed / tr / awk / etc. отфильтруйте вывод, чтобы получить оболочку, на которой выполняется скрипт.

Итак, очищенная выходная версия (работает для Mac или Linux OS работает):

#!/usr/bin/env sh
pstree  -p $$  | tr ' ()' '\012\012\012' | grep -i "sh$" | grep -v "$0" | tail -1

На бегу дает:

./test.sh 
sh

И при запуске с другой оболочкой:

#!/usr/bin/env ksh
pstree  -p $$  | tr ' ()' '\012\012\012' | grep -i "sh$" | grep -v "$0" | tail -1

Урожайность:

./test.sh 
ksh

Нет корневой или специальной файловой системы не требуется. Обратите внимание, моя фильтрация предполагает, что двоичное имя оболочки заканчивается на sh и что нет промежуточных записей, заканчивающихся на sh. Также предполагается, что вы не назвали свой скрипт "sh" или какой-то неудачный шаблон grep, который уничтожит информацию. :) Потребуется некоторая настройка для вашей собственной среды, чтобы обеспечить более высокую степень защиты от неправильного обращения.

Крыло Тан Вонг
источник
-2

Вы можете использовать команду:

$ echo $SHELL

выяснить оболочку из скрипта.

pradeepchhetri
источник
18
$SHELLэто оболочка по выбору пользователя. Инициализируется из логина оболочки пользователя. Ничего общего с текущей запущенной оболочкой.
Стефан Шазелас