런타임 동안 스크립트에서 쉘을 결정


22

내 지식에 따라 현재 쉘을 결정하기 위해 쉘 echo $0에서 사용 합니다. 오히려 스크립트가 실행중인 쉘을 체크인하기를 원합니다. 그래서 $0스크립트 로 인쇄하려고 시도했을 때 스크립트 이름을 반환합니다. 그래서 내 질문은 런타임 중에 스크립트가 실행중인 쉘을 어떻게 찾을 수 있습니까?


어떤 스크립팅 언어를 사용하고 있습니까? 또한 최악의 경우, 항상 스크립트 내에서 "echo $ 0"결과를 얻기 위해 시스템 명령을 쉘할 수 있습니다.
BriGuy

echo $0스크립트는 많은 다른 컴퓨터에서 실행되므로 먼저 확인해야 할 것은 쉘입니다.
g4ur4v

그렇다면 스크립팅 언어는 무엇입니까?
BriGuy

@BriGuy : 유닉스 쉘 스크립트입니다.
g4ur4v

3
#! /bin/sh -맨 위에 추가하면 에서 실행됩니다 sh. 당신은 의미합니까 어떤 변종 sh이이다?
Stéphane Chazelas

답변:


28

리눅스에서는을 사용할 수 있습니다 /proc/PID/exe.

예:

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

3
그것은 나에게 너무 구체적입니다 (예 : 데비안에서는 zsh4 또는 ksh93을 인쇄합니다). /bin/sed -r -e 's/\x0.*//' /proc/$$/cmdline대신 zsh 또는 ksh를 제공합니다. (쉘이 대신 마법의 이름으로 스크립트 이름을 지정하지 않은 경우 $ 0입니다.)
frostschutz

@frostschutz Yours는 +500에 대한 최고의 답변입니다!
Teresa e Junior

5
이것은 전 세계의 무서운 리눅스 박스 질병으로 고통 받고 있습니다 . /proc그것이 추한만큼 추악하고 휴대 할 수 없습니다.
Jens

7
@Jens 이것이 내가 리눅스에만 적용하도록 지정한 이유입니다. /proc'추악한'이 아닙니다. /proc종종 매우 우아한 솔루션입니다. 포터블은 가능하지만 포터블이 가능하기 때문에 추악한 것은 아닙니다.
Patrick

3
@ 패트릭 /proc파일의 파일이 개발자의 변덕에 빠질 수 있으며 파일의 내용이 예고없이 변경되기 쉽기 때문에 추악한 것으로 간주 됩니다.
Jens

48

아마도 당신이 요구하는 것이 아닐 수도 있지만, 이것은 톰슨 (osh), 본, 본 아가 (bash), Korn (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 } *///'''

유즈넷에 2004 년경 which_interpreter 스크립트 의 초기 버전을 게시했습니다 . Sven Mascheck에는 Bourne과 같은 쉘을 식별하는 데 중점을 둔 whatshell 이라는 스크립트가 있습니다 . 당신은 또한 우리의 두 스크립트의 병합 된 버전을 찾을 수 있다 .


3
이것은 Python 3, Python 2 만 식별 할 수 없습니다.이를 수정하려면 print함수로 변경하십시오 .
Chris Down

39
지금까지 가장 큰 WTF 순간입니다. 정신력을 넘어 이동성을 가져다 +1
l0b0

1
생선 껍질을 인식하면 좋을 것입니다.
Konrad Borowski

2
@ xfix, PHP와 자바 스크립트를 추가하기 전에 시도했지만 기억할 수 없었습니다. 지원할 언어 수가 많아짐에 따라 복잡성이 기하 급수적으로 증가합니다 (추가 된 모든 언어가 지원되는 모든 언어에서 유효하거나 최소한 눈에 띄지 않는 부작용을 가져야 함). 이제 훨씬 더 어려워 질 것입니다. 불가능하다는 말은 아니지만 다른 언어에 대한 지원을 중단하는 것을 의미합니다.
Stéphane Chazelas

4
@iconoclast이므로 bash 3.2.53(1)-release해석하는 인터프리터로 올바르게 식별 됩니다.
Stéphane Chazelas

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 에서 왔으며 결코 만들어지지 않았습니다.
Stéphane Chazelas

그렇기 때문에에 대한 두 번째 테스트가 FCEDIT있습니다.
Jens

1
권리. 참고 posh이 가능성 비록 하나의 로그인 쉘로 가지고 들어, (당신은 아마 "쉬"를 호출 할 것이다, 그래서 비 POSIX 제거 기능 대부분과 pdksh 같은)은 더 FCEDIT가 없습니다도 KSH_VERSION하지만 (아마 오랫동안) PS3를 가지고 . 또한 위의 코드 여부를 반영하지 않을 것이라고주의 bashzshsh당신이 사용하는 경우 문제가있을 수 있습니다 에뮬레이션 모드, $PROFILE_SHELL이런 저런 기능을 사용할지 여부를 결정할 수 있습니다. 참조 스벤 Mascheck의 whatshell을 당신이 (또는하지 않을 수) 확인 할 수 있습니다 이상.
Stéphane Chazelas

6

당신은 시도 할 수 있습니다

ps -o args= -p "$$"

스크립트의 pid와 관련된 명령의 이름이 표시됩니다.


내가 알 수있는 한 shebang을 사용할 때 작동하지 않습니다. sprunge.us/QeHD
Chris Down

죄송합니다, @ChrisDown, Flup. 내 나쁜, 나는 대답을 POSIXifying cmdcomm때 잘못 번역 되었습니다 .
Stéphane Chazelas

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하면 쉘 부모에 대한 경로를 얻습니다.
Thor

POSIX sh에는 $PPID변수가 있습니다. 에 Linux사용할 수 있습니다 readlink -f "/proc/$PPID/exe".
Stéphane 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의 출력 형식과 스타일은 환경에 따라 다르지만 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. 사용자가 선택한 쉘입니다. 사용자의 로그인 쉘에서 초기화되었습니다. 현재 실행중인 쉘과 관련이 없습니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.