在运行时确定脚本中的shell


22

据我所知,要确定我们echo $0在外壳中使用的当前外壳。而是我希望我的脚本检查它在哪个外壳中运行。因此,我尝试$0在脚本中进行打印,并按原样返回了脚本的名称。因此,我的问题是如何找到运行时脚本运行在哪个shell中?


您正在使用哪种脚本语言?同样,在更坏的情况下,您总是可以掏出一个系统命令来在脚本中获取“ echo $ 0”结果。
BriGuy

echo $0在这里不是一个选择,因为脚本将在许多不同的机器上运行,而我首先要检查的是shell。
g4ur4v 2013年

那么脚本语言是什么?
BriGuy

@BriGuy:这是一个Unix Shell脚本。
g4ur4v

3
好吧,如果您#! /bin/sh -在顶部添加,它将在中运行sh。你是说它什么变体sh
斯特凡Chazelas

Answers:


28

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

例:

# readlink /proc/$$/exe
/bin/zsh

3
这对我来说太具体了(例如,在Debian上它显示zsh4或ksh93)。/bin/sed -r -e 's/\x0.*//' /proc/$$/cmdline给出的是zsh或ksh。(如果shell没有神奇地解决这个问题,而是给脚本命名,那将是$ 0)。
frostschutz

@frostschutz您的最佳答案,为+500!
Teresa e Junior

5
这遭受了可怕的全世界Linux盒疾病的困扰。/proc就像它一样丑陋且难以携带。
Jens

7
@Jens这就是为什么我指定仅适用于Linux。/proc并不“丑陋”。/proc通常是一个非常优雅的解决方案。是的,是不可移植的,但是因为某些东西是不可移植的,所以它并不难看。
Patrick

3
@Patrick我认为这很/proc丑陋,因为其中的文件可能会随开发人员的想法而来去去,并且文件的内容易于更改而不会发出通知,由于bitrot和移动目标文件格式而引起无尽的痛苦。
Jens

48

也许不是您的要求,但这在某种程度上可以确定当前正在解释它的解释器,例如Thompson(osh),Bourne,Bourne-again(bash),Korn(ksh88,ksh93,pdksh,mksh ),zsh,符合政策的普通(posh),Yet Another(yash),rc,akanga,es shell,wish,tclsh,expect,perl,python,ruby,php,JavaScript(nodejs,SpiderMonkey shell和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 } *///'''

我在2004年左右在usenet上发布了which_interpreter 脚本的初始版本。Sven Mascheck有一个名为whatshell的脚本(可能对您更有用),该脚本专注于识别类似Bourne的外壳。您还可以在此处找到我们两个脚本的合并版本。


3
它不能识别Python 3,只能识别Python2。要解决此问题,请更改print为一个函数。
克里斯·

39
这是迄今为止今年最大的WTF时刻。+1使便携性超越了理智。
l0b0

1
如果能识别出鱼壳,那就太好了。
Konrad Borowski

2
@xfix,我记得甚至在添加php和javascript之前都尝试过,但是那时找不到解决方案。随着要支持的语言数量的增加,复杂性呈指数级增长(因为您添加的所有内容在所有受支持的语言中都必须有效(或至少具有不明显的副作用)),因此现在变得更加困难。我并不是说这是不可能的,但这可能意味着放弃对某些其他语言的支持。
斯特凡Chazelas

4
@iconoclast,因此它正确地标识bash 3.2.53(1)-release为解释它的解释器。
斯特凡Chazelas

12

这就是我在.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

1
请注意,只有非常最近的版本ksh93都有$KSH_VERSION。该变量来自pdkshAT&T ksh88,但从未传给它。
斯特凡Chazelas

是的,这就是为什么我要进行第二次测试FCEDIT
詹斯

1
对。请注意posh(pdksh已删除了大多数非POSIX功能,因此您可能希望将其称为“ sh”)没有FCEDIT或KSH_VERSION,但具有PS3(可能不会持续很长时间),尽管不太可能将其作为登录shell 。另外请注意,上面的代码将不能反映是否bash或者zshsh如果你使用仿真模式,这可能是一个问题$PROFILE_SHELL,以决定是否要启用这个或那个功能。另请参阅Sven Mascheck的whatshell,您可能想要(也可能不想)检查的更多内容。
斯特凡Chazelas

6

你可以试试

ps -o args= -p "$$"

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


据我所知,使用shebang时不起作用。sprunge.us/QeHD-
克里斯·

抱歉,@ ChrisDown,Flum。我的坏,我曾错误地转换cmdcommPOSIXifying答案的时候。
斯特凡Chazelas

1

如果lsof您的系统上有可用的命令,则可以通过获取父PID ps并解析其输出来获取父Shell可执行文件的完整路径lsof -p $ppid(请参阅如何确定我正在使用的当前Shell?)。

#!/bin/sh
ppid="`ps -p "$$" -o ppid=`"
lsof -nP -p "$ppid" | awk 'NR==3 {print $NF; exit}'

在我的系统上/,如果我使用,则返回NR==4shell父级的路径。
雷神

请注意,POSIX sh具有$PPID变量。开启Linux,即可使用readlink -f "/proc/$PPID/exe"
斯特凡Chazelas

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输出的格式和样式取决于您的环境,但是您可以强制执行A​​SCII输出,然后执行sed / tr / awk / etc。过滤输出以获取运行脚本的shell。

因此,需要清理输出版本(适用于Mac或Linux OS):

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

运行收益:

./test.sh 
sh

当使用不同的shell运行时:

#!/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

从脚本中找出外壳。


18
$SHELL是用户选择的外壳。从用户的登录外壳初始化。与当前正在运行的外壳无关。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.