determinar shell no script durante o tempo de execução


22

De acordo com meu conhecimento, para determinar o shell atual que usamos echo $0no shell. Em vez disso, quero que meu script verifique em qual shell ele está sendo executado. Então, tentei imprimir $0o script e ele retorna o nome do script como deveria. Então, minha pergunta é como posso encontrar em qual shell meu script está sendo executado durante o tempo de execução?


qual linguagem de script você está usando? Além disso, na pior das hipóteses, você sempre pode extrair um comando do sistema para obter os resultados "echo $ 0" dentro do script.
BriGuy

echo $0não é uma opção aqui, pois o script será executado em muitas máquinas diferentes, onde a primeira coisa que precisarei verificar é o shell.
G4ur4v

Então, qual é a linguagem de script então?
BriGuy

@BriGuy: É um script shell unix.
G4ur4v

3
Bem, se você adicionar #! /bin/sh -no topo, ele será executado sh. Você quer dizer de que variante shé?
Stéphane Chazelas 04/04

Respostas:


28

No Linux você pode usar /proc/PID/exe.

Exemplo:

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

3
Isso é um pouco específico demais para mim (por exemplo, no Debian, ele imprime zsh4 ou ksh93). /bin/sed -r -e 's/\x0.*//' /proc/$$/cmdlinedá zsh ou ksh. (Seria US $ 0 se as conchas não corrigissem magicamente isso para dar o nome dos scripts).
Frostschutz

@frostschutz A sua é a melhor resposta, concorra a +500!
Teresa e Junior

5
Isso sofre com a temida doença do mundo todo, uma caixa Linux . /procé o mais feio e portável possível.
Jens

7
@ Jens, é por isso que eu especifiquei isso se aplica apenas ao Linux. /procnão é 'feio'. /procgeralmente é uma solução muito elegante. Não portável sim, mas porque algo é portável não o torna feio.
Patrick

3
@Patrick Considero /procfeio porque os arquivos nele podem ir e vir ao capricho dos desenvolvedores e o conteúdo dos arquivos é passível de alterações sem aviso prévio, causando uma dor sem fim devido ao bitrot e aos formatos de arquivo de destino em movimento.
Jens

48

Talvez não seja o que você está pedindo, mas isso deve funcionar até certo ponto para identificar o intérprete atualmente interpretando-o para alguns como Thompson (osh), Bourne, Bourne-again (bash), Korn (ksh88, ksh93, pdksh, mksh ), zsh, Ordinário compatível com a política (posh), Yet Another (yash), rc, akanga, es shells, desejo, tclsh, expect, perl, python, ruby, php, JavaScript (nodejs, SpiderMonkey shell e JSPL, pelo menos) , 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 } *///'''

Publiquei a versão inicial do script which_interpreter por volta de 2004 na usenet. Sven Mascheck tem um script (provavelmente mais útil para você) chamado whatshell, que se concentra na identificação de conchas semelhantes a Bourne. Você também pode encontrar uma versão mesclada de nossos dois scripts .


3
Isso não pode identificar o Python 3, apenas o Python 2. Para corrigir isso, mude printpara ser uma função.
Chris Baixo

39
Este é o maior momento do WTF do ano até agora. +1 por levar a portabilidade à sanidade.
L0b0

1
Seria bom se reconhecesse casca de peixe.
Konrad Borowski

2
@ xfix, eu lembro de tentar antes mesmo de adicionar php e javascript, mas não consegui encontrar uma solução então. A complexidade cresce exponencialmente com o número de idiomas a serem suportados (como tudo o que você adiciona deve ser válido (ou pelo menos ter efeitos colaterais imperceptíveis) em todos os idiomas suportados), por isso seria ainda mais difícil agora. Não estou dizendo que é impossível, mas isso provavelmente significaria abandonar o suporte para outros idiomas.
Stéphane Chazelas 23/03

4
@iconoclast, para que seja identificado corretamente bash 3.2.53(1)-releasecomo o intérprete que o interpreta.
Stéphane Chazelas

12

É isso que eu uso no meu .profile para verificar vários shells nos sistemas em que trabalho. Não faz distinções finas entre ksh88 e ksh93, mas nunca me falhou.

Observe que ele não requer um único garfo ou tubo.

# 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
Observe que apenas versões muito recentes do ksh93have $KSH_VERSION. Essa variável vem pdkshe nunca chegou à AT&T ksh88.
Stéphane Chazelas

Certo, e é por isso que eu tenho o segundo teste FCEDIT.
Jens

1
Direita. Observe que posh(pdksh com a maioria dos recursos não POSIX removidos, então você provavelmente chamaria de "sh") não possui FCEDIT nem KSH_VERSION, mas possui PS3 (talvez não por muito tempo), embora seja improvável que alguém o tenha como shell de login . Observe também que o código acima não refletirá se está bashou zshnão no shmodo de emulação, o que pode ser um problema se você estiver usando $PROFILE_SHELLpara decidir se deseja ativar ou não esse recurso. Veja também o whatshell de Sven Mascheck para mais informações que você pode (ou não) querer verificar.
Stéphane Chazelas 16/04

6

Você poderia tentar

ps -o args= -p "$$"

que fornecerá o nome do comando associado ao pid do script.


Não funciona ao usar um shebang, tanto quanto eu posso dizer. sprunge.us/QeHD
Chris Down

Desculpe, @ChrisDown, Flup. Meu mal, eu tinha traduzido incorretamente cmdpara commquando POSIXIFICAR a resposta.
Stéphane Chazelas 04/04

1

Se houver o lsofcomando disponível no seu sistema, você poderá obter o caminho completo do executável do shell pai, obtendo o PID pai pse analisando a saída de lsof -p $ppid(consulte Como determinar o shell atual no qual estou trabalhando? ).

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

No meu sistema, isso retorna /, se eu usar NR==4, recebo o caminho para o pai dos shells.
Thor

Observe que os POSIX shs têm a $PPIDvariável Ativado Linux, você pode usar readlink -f "/proc/$PPID/exe".
Stéphane Chazelas

1

Fora do território Linux ou sem acesso ao sistema de arquivos / proc ou equivalente, você pode usar o pstree:

Supondo que você tenha o orgulho de

Em um 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

Em uma caixa Linux:

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

O formato e o estilo da saída da pstree diferem, dependendo do seu ambiente, mas você pode aplicar a saída ASCII e, em seguida, sed / tr / awk / etc. filtre a saída para obter o shell que está executando o script.

Portanto, uma versão de saída limpa (funciona para Mac OS ou Linux):

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

Rendimentos de execução:

./test.sh 
sh

E quando executado com um shell diferente:

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

Rendimentos:

./test.sh 
ksh

Não é necessário nenhum sistema de arquivos raiz ou especial. Observe que minha filtragem pressupõe que o nome binário do shell termine com sh e que não haja entradas intermediárias que terminem com sh. Também pressupõe que você não nomeou seu script "sh" ou algum padrão de grep infeliz que obliterará as informações. :) Exigirá alguma personalização para o seu próprio ambiente, a fim de garantir um maior grau de proteção contra falhas.


-2

Você pode usar o comando:

$ echo $SHELL

para descobrir o shell de dentro do script.


18
Não. $SHELLÉ o shell de escolha do usuário. Inicializado a partir do shell de login do usuário. Nada a ver com o shell atualmente em execução.
Stéphane Chazelas 04/04
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.