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


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를 가지고 . 또한 위의 코드 여부를 반영하지 않을 것이라고주의 bash나 zsh에 sh당신이 사용하는 경우 문제가있을 수 있습니다 에뮬레이션 모드, $PROFILE_SHELL이런 저런 기능을 사용할지 여부를 결정할 수 있습니다. 참조 스벤 Mascheck의 whatshell을 당신이 (또는하지 않을 수) 확인 할 수 있습니다 이상.
— Stéphane Chazelas

6

당신은 시도 할 수 있습니다

ps -o args= -p "$$"

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


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

죄송합니다, @ChrisDown, Flup. 내 나쁜, 나는 대답을 POSIXifying cmd할 comm때 잘못 번역 되었습니다 .
— 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.