実行時にスクリプト内のシェルを決定します


22

私の知る限りでは、シェルで使用echo $0している現在のシェルを判別するために。むしろ、どのシェルで実行されているかをスクリプトに確認してもらいたいです。そのため$0、スクリプトで印刷しようとしましたが、スクリプトの名前が正しく返されます。だから、私の質問は、実行中にスクリプトが実行されているシェルをどのように見つけることができますか?


どのスクリプト言語を使用していますか?また、最悪の場合、システムコマンドをいつでも実行して、スクリプト内で "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 Yoursがベストアンサーです。+ 500で走りましょう!
テレサeジュニア

5
これは恐ろしいすべての世界のLinuxボックス病に苦しんでいます/procそれは得るのと同じくらいくて移植性がありません。
イェンス

7
@Jensは、これがLinuxにのみ適用されると指定した理由です。/proc「ugい」ではありません。/proc多くの場合、非常にエレガントなソリューションです。可搬性はい。ただし、可搬性がないからといってくありません。
パトリック

3
@Patrick /procその中のファイルは開発者の気まぐれに出入りする可能性があり、ファイルの内容は予告なしに変更される傾向があり、bitrotと移動するターゲットファイル形式による無限の痛みを引き起こすため、私はugいと思います。
イェンス

48

たぶんあなたが求めているものではないかもしれませんが、これはある程度トンプソン(osh)、ボーン、ボーン-アゲイン(bash)、コーン(ksh88、ksh93、pdksh、mksh)のために現在通訳している通訳を識別するためにある程度機能するはずです)、zsh、ポリシー準拠の通常(posh)、Yet Another(yash)、rc、akanga、es shells、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 } *///'''

そのwhich_interpreter スクリプトの最初のバージョンを2004年頃にusenet に投稿しました。Sven Mascheckには、Bourneに似たシェルの識別に焦点を当てたwhatshellと呼ばれる(おそらくより便利な)スクリプトがあります。また、2つのスクリプトのマージされたバージョンもあります。


3
これは、Python 2のみをPython 3として識別することはできません。これを修正するには、print関数に変更します。
クリスダウン

39
これは、これまでで最大のWTFの瞬間です。健全性を超えて移植性を得るための+1。
l0b0

1
魚の殻を認識できればいいですね。
コンラッドボロウスキ14年

2
@ xfix、phpとjavascriptを追加する前でも試したことを覚えていますが、解決策が見つかりませんでした。サポートする言語の数に応じて複雑さが指数関数的に増大します(追加するすべてがサポートされているすべての言語で有効である(または少なくとも気付かない副作用がなければならないため)ので、今ではさらに困難になります。私はそれが不可能だと言っているわけではありませんが、それはおそらく他の言語のサポートをやめることを意味するでしょう。
ステファンシャゼル14年

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

1
のごく最近のバージョンのみがksh93持っていることに注意してください$KSH_VERSION。この変数はpdkshAT&T ksh88 から来たものであり、AT&T ksh88には到達していません。
ステファンシャゼル

そう、だからこそ私はのための2番目のテストを持っていFCEDITます。
イェンス

1
右。注意posh1がログインシェルとしてそれを持っているため、それはそうだけれども(あなたはおそらく、「SH」、それを呼び出すようにしたいと思うので、ほとんどの非POSIXが削除された機能でpdkshのは)、何FCEDITもKSH_VERSIONを持っていないが、PS3(そうでないかもしれないために長い)を持っています。また、上記のコードがいるかどうかを反映しないことに注意しbashたりzshしているsh、使用している場合は問題になるかもしれエミュレーションモード、$PROFILE_SHELLこのまたはその機能を有効にするかどうかを決定します。確認したい(またはしない)詳細については、Sven Mascheckのwhatshellも参照してください。
ステファンシャゼル

6

試すことができます

ps -o args= -p "$$"

これにより、スクリプトのpidに関連付けられたコマンドの名前がわかります。


私が知る限り、シバンを使用する場合は機能しません。sprunge.us/QeHD
クリスダウン

すみません、@ ChrisDown、Flup。悪いのは、答えをPOSIX化cmdするcommときに間違って翻訳していたことです。
ステファンシャゼル

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"
ステファンシャゼル14

1

Linux以外の場所、または/ procファイルシステムへのアクセス権がない、または同等の場合は、pstreeを使用できます。

あなたのpidを持っていると仮定して

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

スクリプト内からシェルを見つけます。


18
いいえ$SHELL。ユーザーが選択するシェルです。ユーザーのログインシェルから初期化されます。現在実行中のシェルとは関係ありません。
ステファンシャゼル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.