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?

g4ur4v
fonte
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
Patrick
fonte
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 .

Stéphane Chazelas
fonte
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
Jens
fonte
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.

Flup
fonte
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}'
mari
fonte
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.

Wing Tang Wong
fonte
-2

Você pode usar o comando:

$ echo $SHELL

para descobrir o shell de dentro do script.

pradeepchhetri
fonte
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