Çalışma zamanı sırasında komut dosyasında kabuk belirlemek


22

Bildiğim kadarıyla echo $0, kabuğunda kullandığımız mevcut kabuğu belirlemek için . Aksine betiğimin hangi kabuğun çalıştığını kontrol etmesini istiyorum. Bu yüzden, $0komut dosyasında yazdırmayı denedim ve komut dosyasının adını gerektiği gibi döndürür. Öyleyse sorum şu, çalışma zamanında betiğimin hangi kabuğu çalıştırdığını nasıl bulabilirim?


hangi kodlama dilini kullanıyorsunuz Ayrıca, daha kötüsü, her zaman betiğin içinde "echo $ 0" sonuçlarını elde etmek için bir sistem komutu koyabilirsiniz.
BriGuy,

echo $0buradaki bir seçenek değildir, çünkü senaryo, kontrol edeceğim ilk şeyin kabuk olduğu birçok farklı makinede çalışacaktır.
g4ur4v

Peki komut dosyası dili o zaman?
BriGuy

@BriGuy: Bu bir unix kabuk betiği.
g4ur4v

3
#! /bin/sh -En üste eklerseniz , yayınlanacak sh. Ne tür bir değişkensh
Stéphane Chazelas

Yanıtlar:


28

Linux üzerinde kullanabilirsiniz /proc/PID/exe.

Örnek:

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

3
Bu benim için çok özel (örneğin Debian'da zsh4 veya ksh93'ü basıyor). /bin/sed -r -e 's/\x0.*//' /proc/$$/cmdlinebunun yerine zsh veya ksh verir. (Kabuklar, komut dosyası adını vermek için sihirli bir şekilde düzelmediyse bu 0 dolar olurdu).
frostschutz

@frostschutz Sizinki en iyi cevap, +500 için koş!
Teresa e Junior,

5
Bu korkunç Tüm dünyada bir Linux kutu hastalığından muzdarip . /proco kadar çirkin ve taşınabilir.
Jens

7
@Jens bu yüzden bunun sadece Linux için geçerli olduğunu belirttim. /proc'çirkin' değil. /procgenellikle çok zarif bir çözümdür. Portatif evet, ama portatif olmayan bir şey çirkin yapmaz çünkü.
Patrick,

3
@Patrick /procÇirkin olduğunu düşünüyorum çünkü içerisindeki dosyalar geliştiricilerin kaprisine girebilir ve dosyaların içeriği önceden haber verilmeksizin değişebilir, bu da bitrot ve hareketli hedef dosya formatları nedeniyle sonsuz acıya neden olur.
Jens

48

Belki de istediğin şey değil, ama bu, bir süredir, Thompson (osh), Bourne, Bourne-yeniden (bash), Korn (ksh88, ksh93, pdksh, mksh gibi) için yorum yapan tercümanı tanımlamak için çalışmalıdır. ), zsh, Politika uyumlu Olağan (lüks), Yine Başka (yaş), rc, akanga, es kabukları, dilek, tclsh, bekle, perl, python, yakut, php, JavaScript (nodejs, SpiderMonkey kabuğu ve en az JSPL) , MS / Şarap 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 } *///'''

Usenet’te 2004’ün yaklaşık hangisinin yorumlayıcı komut dosyasının ilk sürümünü yayınladım . Sven Mascheck, Bourne benzeri mermileri tanımlamaya odaklanan whatshell adlı bir senaryoya sahiptir. Ayrıca iki betiğimizin birleştirilmiş versiyonunu orada da bulabilirsiniz .


3
Bu Python 3'ü, yalnızca Python 2'yi tanımlayamıyor. Bunu düzeltmek için, printbir işlev olarak değiştirin .
Chris Down,

39
Bu, şu ana kadar yılın en büyük WTF anı. Akıl sağlığı geçmiş taşınabilirliği almak için +1.
l0b0

1
Balık kabuğunu tanımak güzel olurdu.
Konrad Borowski

2
@xfix, php ve javascript eklemeden önce bile denediğimi hatırlıyorum ama o zaman bir çözüm bulamadım. Karmaşıklık, destekleyecek dillerin sayısıyla birlikte katlanarak büyüyor (eklediğiniz her şey geçerli olmalıdır (veya en azından farkedilmeyen yan etkilere sahip olmalıdır), tüm desteklenen dillerde), bu yüzden şimdi daha da zor olurdu. Bunun imkansız olduğunu söylemiyorum ama bu muhtemelen diğer bazı dilleri destekleme anlamına gelir.
Stéphane Chazelas 23:14

4
@conoclast, bu yüzden bash 3.2.53(1)-releasetercümanı tercüman olarak tanımlar .
Stéphane Chazelas 10:15

12

Üzerinde çalıştığım sistemlerdeki çeşitli mermileri kontrol etmek için .profile dosyamda kullandığım şey bu. Ksh88 ve ksh93 arasında ince ayrımlar yapmaz, ama beni asla başarısızlığa uğratmadı.

Tek bir çatal veya boru gerektirmediğini unutmayın.

# 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
Sadece çok yeni sürümlere ksh93sahip olduğuna dikkat edin $KSH_VERSION. Bu değişken geliyor pdkshve AT & T ksh88'e asla giremedi.
Stéphane Chazelas,

Doğru, bu yüzden ikinci sınava girdim FCEDIT.
Jens

1
Sağ. Not o poshda pek mümkün olsa biri, bir giriş kabuğu olarak ona sahip olmak için, (muhtemelen "sh" diyoruz isteyeyim böylece POSIX olmayan kaldırıldı özellikleri En çok pdksh) hiçbir FCEDIT vardır ne de KSH_VERSION ama (belki uzun sürmez) PS3 vardır . Ayrıca yukarıdaki kod olmadığını yansıtmak olmaz unutmayın bashya zshiçindedir shkullandığınız takdirde bir sorun olabilir emülasyon modunda, $PROFILE_SHELLşu ya da bu özelliği etkinleştirmek için olup olmadığına karar için. Ayrıca bkz. Sven Mascheck'in kabuğunu incelemek isteyebileceğiniz (ya da istemeyeceğiniz) daha fazla bilgi için.
Stéphane Chazelas 16:13

6

Deneyebilirsin

ps -o args= -p "$$"

betiğin iadesiyle ilişkili komutun ismini verir.


Bir shebang kullanırken söyleyebileceğim kadarıyla çalışmıyor. sprunge.us/QeHD
Chris Down

Üzgünüz, @ChrisDown, Flup. Benim hatam, yanlış tercüme etmişti cmdiçin commcevap POSIXifying zaman.
Stéphane Chazelas

1

Varsa lsofsisteminizde mevcut komut, sen aracılığıyla ana PID alarak ana kabuk yürütülebilir tam yolunu alabilirsiniz psve çıktıya ayrıştırma lsof -p $ppid(bkz i üzerinde çalışıyorum geçerli kabuk nasıl belirlenir? ).

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

Benim sistemde bu döner /, kullanırsam NR==4ben kabuklar ebeveyne giden yolu alıyorum.
Thor,

POSIX shs $PPIDdeğişkenine sahip olduğunu unutmayın . Açık Linux, kullanabilirsiniz readlink -f "/proc/$PPID/exe".
Stéphane Chazelas 09:14

1

Linux ülkesi dışında veya / proc dosya sistemine ya da eşdeğerine erişimi olmayan, pstree'den yararlanabilirsiniz:

Pid'in olduğunu varsayarsak

Mac'te:

./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

Bir Linux kutusunda:

./test.sh 
14981
bash(14981)---pstree(14982)

Çıktının pstree'den gelen biçimi ve stili, ortamınıza bağlı olarak değişir, ancak ASCII çıktısını ve ardından sed / tr / awk / etc komutunu uygulayabilirsiniz. betiği çalıştıran kabuğu almak için çıktıyı süzün.

Böylece temizlenmiş bir çıktı sürümü (Mac veya Linux işletim sistemi için çalışır):

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

Kaçak verim:

./test.sh 
sh

Ve farklı bir kabukla çalıştırdığınızda:

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

Verim:

./test.sh 
ksh

Kök veya özel bir dosya sistemi gerekmez. Not, filtrelemem kabuk ikili adının sh ile bittiğini ve sh ile biten hiçbir ara giriş olmadığını varsayıyor. Ayrıca betiğinize "sh" veya bilgiyi yok edecek bazı talihsiz bir grep örüntüsü isimlendirmediğinizi varsayalım. :) Daha yüksek seviyede bir sızdırmazlık sağlamak için kendi ortamınız için bazı kişiselleştirmeler yapmanız gerekecektir.


-2

Komutu kullanabilirsiniz:

$ echo $SHELL

Kabuğu betiğin içinden bulmak için.


18
Hayır $SHELL, kullanıcının tercih ettiği kabuktur. Kullanıcının giriş kabuğundan başlatıldı. Şu anda çalışan kabuk ile ilgisi yok.
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.