在运行时确定脚本中的 shell

g4u*_*r4v 34 linux shell-script

据我所知,确定我们echo $0在shell中使用的当前shell。相反,我希望我的脚本检查它正在运行的 shell。所以,我尝试$0在脚本中打印,它返回了它应该的脚本名称。所以,我的问题是如何找到我的脚本在运行时运行在哪个 shell 中?

Sté*_*las 60

也许不是你所要求的,但这应该在某种程度上可以识别当前解释它的口译员

  1. 汤普森壳 ( osh),
  2. 伯恩壳,
  3. Bourne-again shell ( bash),
  4. Korn shell ( ksh88, ksh93, pdksh, mksh),
  5. zsh,
  6. 符合政策的普通外壳 ( posh),
  7. 又一个壳 ( yash),
  8. rc 贝壳,
  9. akanga 贝壳,
  10. es外壳,
  11. wish TCL翻译,
  12. tclsh TCL翻译,
  13. expect TCL翻译,
  14. 珀尔,
  15. Python,
  16. 红宝石,
  17. PHP,
  18. JavaScript(至少是 nodejs、SpiderMonkey shell 和 JSPL)
  19. MS/Wine cmd.execommand.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 } *///'''
Run Code Online (Sandbox Code Playgroud)

我在 2004 年左右在 usenet 上发布了which_interpreter 脚本的初始版本。Sven Mascheck 有一个(可能对您更有用)脚本,称为whatshell,专注于识别 Bourne-like shell。您还可以在那里找到我们两个脚本的合并版本。

  • 这是今年迄今为止最大的WTF时刻。+1 使便携性超越理智。 (50认同)
  • @iconoclast,因此它正确地将`bash 3.2.53(1)-release` 识别为解释它的解释器。 (4认同)
  • 这不能识别 Python 3,只能识别 Python 2。要解决这个问题,请将 `print` 更改为一个函数。 (3认同)
  • 如果它能识别鱼壳就好了。 (3认同)
  • @xfix,我记得在添加 php 和 javascript 之前尝试过,但当时找不到解决方案。复杂性随着要支持的语言数量呈指数级增长(因为您添加的所有内容都必须在所有支持的语言中都是有效的(或至少具有不明显的副作用)),因此现在变得更加困难。我并不是说这是不可能的,但这可能意味着放弃对其他一些语言的支持。 (2认同)
  • @iconoclast,你的意思是你运行了 `zsh ./that-script` 并且它返回了 `bash 3.2.53(1)-release`?更有可能的是你在 `zsh` 中将它作为 `./that-script` 运行,它被你的 `sh` 解释,而你的 `sh` 恰好是 `bash`。 (2认同)

phe*_*mer 35

在 linux 上,您可以使用/proc/PID/exe.

例子:

# readlink /proc/$$/exe
/bin/zsh
Run Code Online (Sandbox Code Playgroud)

  • @Jens 这就是我指定这仅适用于 Linux 的原因。`/proc` 不是“丑陋的”。`/proc` 通常是一个非常优雅的解决方案。不可移植是的,但是因为某些东西不可移植并不会使它变得丑陋。 (9认同)
  • 这患有可怕的*全世界都是 Linux 盒子*疾病。`/proc` 既丑陋又不可移植。 (5认同)
  • 这对我来说有点太具体了(例如在 Debian 上它打印 zsh4 或 ksh93)。`/bin/sed -r -e 's/\x0.*//' /proc/$$/cmdline` 给出 zsh 或 ksh 。(如果 shell 没有神奇地修复它以提供脚本名称,则为 0 美元)。 (3认同)
  • @Patrick 我认为 `/proc` 很丑,因为其中的文件可能会随开发人员的心血来潮来去匆匆,而且文件的内容很容易在没有通知的情况下更改,由于位腐烂和移动目标文件格式而导致无尽的痛苦。 (3认同)

Jen*_*ens 13

这是我在我的 .profile 中用来检查我工作的系统上的各种 shell 的内容。它并没有在 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
Run Code Online (Sandbox Code Playgroud)

  • 正确的。请注意,“posh”(pdksh 删除了大多数非 POSIX 功能,因此您可能希望将其称为“sh”)没有 FCEDIT 也没有 KSH_VERSION,但有 PS3(可能不会太久),尽管人们不太可能拥有它一个登录外壳。另请注意,上面的代码不会反映“bash”或“zsh”是否处于“sh”模拟模式,如果您使用“$PROFILE_SHELL”来决定是否启用这个或那个,这可能会出现问题特征。另请参阅 [Sven Mascheck 的 Whatshell](http://www.in-ulm.de/~mascheck/various/whatshell/) 了解更多您可能(或可能不想)检查的信息。 (2认同)

Flu*_*lup 9

你可以试试

ps -o args= -p "$$"
Run Code Online (Sandbox Code Playgroud)

这将为您提供与脚本的 pid 关联的命令的名称。