déterminer le shell dans le script lors de l'exécution

22

Selon ma connaissance, pour déterminer le shell actuel que nous utilisons echo $0dans le shell. Je veux plutôt que mon script vérifie dans quel shell il s'exécute. J'ai donc essayé d'imprimer $0dans le script et il renvoie le nom du script comme il se doit. Donc, ma question est de savoir comment trouver dans quel shell mon script s'exécute pendant l'exécution?

g4ur4v
la source
quel langage de script utilisez-vous? De plus, dans le pire des cas, vous pouvez toujours décortiquer une commande système pour obtenir les résultats "echo $ 0" à l'intérieur du script.
BriGuy
echo $0n'est pas une option ici, car le script s'exécutera sur de nombreuses machines différentes où la première chose que je devrai vérifier est le shell.
g4ur4v
Alors, quel est le langage de script alors?
BriGuy
@BriGuy: C'est un script shell Unix.
g4ur4v
3
Eh bien, si vous ajoutez #! /bin/sh -en haut, cela fonctionnera sh. Vous voulez dire de quelle variante shs'agit-il?
Stéphane Chazelas

Réponses:

28

Sur Linux, vous pouvez utiliser /proc/PID/exe.

Exemple:

# readlink /proc/$$/exe
/bin/zsh
Patrick
la source
3
C'est un peu trop spécifique pour moi (par exemple, sur Debian, il affiche zsh4 ou ksh93). /bin/sed -r -e 's/\x0.*//' /proc/$$/cmdlinedonne zsh ou ksh à la place. (Ce serait 0 $ si les shells ne corrigeaient pas par magie cela pour donner le nom des scripts à la place).
frostschutz
@frostschutz La vôtre est la meilleure réponse, courez pour le +500!
Teresa e Junior
5
Cela souffre de la redoutable maladie du monde sous Linux . /procest aussi moche et impossible à transporter que possible.
Jens
7
@Jens c'est pourquoi j'ai spécifié que cela s'applique uniquement à Linux. /procn'est pas «moche». /procest souvent une solution très élégante. Unportable oui, mais parce que quelque chose n'est pas transférable ne le rend pas laid.
Patrick
3
@Patrick je considère /proclaid parce que les fichiers qu'il contient peuvent aller et venir au gré des développeurs et le contenu des fichiers est susceptible de changer sans préavis, causant une douleur sans fin en raison de Bitrot et du déplacement des formats de fichiers cibles.
Jens
48

Peut-être pas ce que vous demandez, mais cela devrait fonctionner dans une certaine mesure pour identifier l'interprète qui l'interprète actuellement pour quelques-uns comme Thompson (osh), Bourne, Bourne-again (bash), Korn (ksh88, ksh93, pdksh, mksh ), zsh, Ordinaire conforme à la politique (chic), Yet Another (yash), rc, akanga, es shells, wish, tclsh, expect, perl, python, ruby, php, JavaScript (nodejs, SpiderMonkey shell and JSPL at least) , 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 } *///'''

J'ai posté la version initiale de ce script which_interpreter vers 2004 sur usenet. Sven Mascheck a un script (probablement plus utile pour vous) appelé Whatshell qui se concentre sur l'identification des obus de type Bourne. Vous pouvez également trouver une version fusionnée de nos deux scripts .

Stéphane Chazelas
la source
3
Cela ne peut pas identifier Python 3, seulement Python 2. Pour résoudre ce problème, changez printpour être une fonction.
Chris Down
39
C'est le plus grand moment WTF de l'année jusqu'à présent. +1 pour avoir porté la portabilité au-delà de la raison.
l0b0
1
Ce serait bien s'il reconnaissait la carapace de poisson.
Konrad Borowski
2
@xfix, je me souviens d'avoir essayé avant même d'ajouter du php et du javascript mais je n'ai pas pu trouver de solution à ce moment-là. La complexité augmente de façon exponentielle avec le nombre de langues à prendre en charge (car tout ce que vous ajoutez doit être valide (ou au moins avoir des effets secondaires imperceptibles) dans toutes les langues prises en charge), ce serait donc encore plus difficile maintenant. Je ne dis pas que c'est impossible, mais cela signifierait probablement la suppression du support pour d'autres langues.
Stéphane Chazelas
4
@iconoclast, donc il s'identifie correctement bash 3.2.53(1)-releasecomme l'interprète qui l'interprète.
Stéphane Chazelas
12

C'est ce que j'utilise dans mon .profile pour vérifier les différents shells sur les systèmes sur lesquels je travaille. Il ne fait pas de fines distinctions entre ksh88 et ksh93, mais il ne m'a jamais fait défaut.

Notez qu'il ne nécessite pas une seule fourche ou tuyau.

# 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
la source
1
Notez que seules les versions très récentes de ksh93have $KSH_VERSION. Cette variable vient de pdkshet n'a jamais atteint AT&T ksh88.
Stéphane Chazelas
D'accord, c'est pourquoi j'ai le deuxième test FCEDIT.
Jens
1
Droite. Notez que posh(pdksh avec la plupart des fonctionnalités non-POSIX supprimées, vous voudrez probablement l'appeler "sh") n'a pas FCEDIT ni KSH_VERSION mais a PS3 (peut-être pas pour longtemps), bien qu'il soit peu probable que l'un l'ait comme shell de connexion . Notez également que le code ci - dessus ne refléterait pas si bashou zshsont en shmode d'émulation, qui peut être un problème si vous utilisez $PROFILE_SHELLpour décider si oui ou non pour permettre à ce ou cette fonctionnalité. Voir aussi le Whatshell de Sven Mascheck pour en savoir plus que vous pouvez (ou ne pas vouloir) vérifier.
Stéphane Chazelas
6

Tu pourrais essayer

ps -o args= -p "$$"

qui vous donnera le nom de la commande associée au pid du script.

Flup
la source
Ne fonctionne pas lors de l'utilisation d'un shebang pour autant que je sache. sprunge.us/QeHD
Chris Down
Désolé, @ChrisDown, Flup. Mon mauvais, j'avais incorrectement traduit cmden commlors de la POSIXification de la réponse.
Stéphane Chazelas
1

Si la lsofcommande est disponible sur votre système, vous pouvez obtenir le chemin complet de l'exécutable du shell parent en obtenant le PID parent via pset en analysant la sortie de lsof -p $ppid(voir Comment déterminer le shell actuel sur lequel je travaille? ).

#!/bin/sh
ppid="`ps -p "$$" -o ppid=`"
lsof -nP -p "$ppid" | awk 'NR==3 {print $NF; exit}'
mari
la source
Sur mon système, cela revient /, si j'utilise, NR==4j'obtiens le chemin vers le parent de shell.
Thor
Notez que les POSIX shont la $PPIDvariable. On Linux, vous pouvez utiliser readlink -f "/proc/$PPID/exe".
Stéphane Chazelas
1

En dehors de la terre Linux ou n'ayant pas accès au système de fichiers / proc ou équivalent, vous pouvez utiliser pstree:

En supposant que vous ayez le pid de

Sur un 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

Sur une box Linux:

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

Le format et le style de la sortie de pstree diffèrent selon votre environnement, mais vous pouvez appliquer la sortie ASCII puis sed / tr / awk / etc. filtrez la sortie pour obtenir le shell qui exécute le script.

Donc, une version de sortie nettoyée (fonctionne pour les exécutions Mac ou Linux OS):

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

Rendements à la volée:

./test.sh 
sh

Et lorsqu'il est exécuté avec un autre shell:

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

Rendements:

./test.sh 
ksh

Aucun système de fichiers racine ou spécial requis. Remarque, mon filtrage suppose que le nom binaire du shell se termine par sh et qu'il n'y a pas d'entrées intermédiaires se terminant par sh. Suppose également que vous n'avez pas nommé votre script "sh" ou un motif de grep malheureux qui effacera les informations. :) Il faudra une certaine personnalisation pour votre propre environnement afin d'assurer un degré plus élevé de résistance à toute épreuve.

Wing Tang Wong
la source
-2

Vous pouvez utiliser la commande:

$ echo $SHELL

pour découvrir le shell à partir du script.

pradeepchhetri
la source
18
Non, $SHELLc'est la coque de choix de l'utilisateur. Initialisé à partir du shell de connexion de l'utilisateur. Rien à voir avec le shell en cours d'exécution.
Stéphane Chazelas