визначити оболонку в скрипті під час виконання


22

Згідно з моїми знаннями, для визначення поточної оболонки, яку ми використовуємо echo $0в оболонці. Швидше я хочу, щоб мій сценарій перевірив, в якій оболонці він працює. Отже, я спробував надрукувати $0сценарій, і він повертає назву сценарію як слід. Отже, моє запитання полягає в тому, як я можу знайти, в якій оболонці працює мій сценарій під час виконання?


якою мовою сценаріїв ви користуєтесь? Крім того, гірший випадок, ви завжди можете розгорнути системну команду, щоб отримати результати "echo $ 0" всередині сценарію.
BriGuy

echo $0тут не є варіантом, оскільки сценарій буде працювати на багатьох різних машинах, де перше, що мені потрібно перевірити, - це оболонка.
g4ur4v

То яка тоді сценарна мова?
BriGuy

@BriGuy: Це сценарій оболонки Unix.
g4ur4v

3
Ну, якщо ви додасте #! /bin/sh -вгорі, він запуститься sh. Ви маєте на увазі, який це варіант sh?
Стефан Шазелас

Відповіді:


28

На Linux можна використовувати /proc/PID/exe.

Приклад:

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

3
Це трохи занадто специфічно для мене (наприклад, на Debian він друкує zsh4 або ksh93). /bin/sed -r -e 's/\x0.*//' /proc/$$/cmdlineдає замість zsh або ksh. (Це було б 0 доларів, якщо оболонки не зафіксували це магічним чином, щоб натомість дати ім'я сценаріїв).
frostschutz

@frostschutz Ваша найкраща відповідь, бігайте за +500!
Teresa e Junior

5
Це страждає від жахливої в усьому світі хвороби Linux . /procнастільки потворна і непридатна, як це стає.
Єнс

7
@Jens, тому я вказав, що це стосується лише Linux. /procне є "потворним". /procчасто є дуже елегантним рішенням. Нездатне так, але те, що щось нерепортажне, не робить це некрасивим.
Патрік

3
@Patrick Я вважаю /procнекрасивим, тому що файли в ньому можуть надходити і виходити на примху розробників, а вміст файлів схильний змінюватися без попередження, викликаючи нескінченний біль через бітрот і переміщення цільових форматів файлів.
Єнс

48

Можливо, не те, про що ви просите, але це повинно працювати певною мірою, щоб визначити інтерпретатора, який зараз його інтерпретує, для кількох, таких як Томпсон (ош), Борн, Борн-знову (баш), Корн (ksh88, ksh93, pdksh, mksh ), zsh, сумісний з політикою звичайний (posh), ще один (yash), rc, akanga, es оболонки, побажання, tclsh, очікувати, perl, python, ruby, php, JavaScript (принаймні nodejs, оболонка SpiderMonkey та 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 } *///'''

Я розмістив початкову версію цього сценарію Which_interpreter близько 2004 року на Usenet. У Свена Маскека є (напевно, більш корисний для вас) сценарій під назвою whatshell, який зосереджений на виявленні оболонок Борна. Ви також можете знайти злиту версію наших двох сценаріїв там .


3
Це не може ідентифікувати Python 3, лише Python 2. Щоб виправити це, змініть printфункцію.
Кріс Даун

39
Це найбільший момент WTF за рік. +1 за прийняття мобільності минулого розуму.
l0b0

1
Було б добре, якби він розпізнав рибну шкаралупу.
Конрад Боровський

2
@xfix, я пам’ятаю, що намагався ще до того, як додати php та javascript, але тоді не міг знайти рішення. Складність зростає в експоненціальній кількості мов, які потрібно підтримувати (оскільки все, що ви додаєте, має бути дійсним (або принаймні мати непомітні побічні ефекти) у всіх підтримуваних мовах), тому це буде ще складніше. Я не кажу, що це неможливо, але це, мабуть, означатиме відмову від підтримки інших мов.
Стефан Шазелас

4
@iconoclast, тому він правильно ідентифікується bash 3.2.53(1)-releaseяк інтерпретатор, що його інтерпретує.
Стефан Шазелас

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. Ця змінна походить від pdkshі ніколи не переходила до AT&T ksh88.
Стефан Шазелас

Правильно, саме тому я маю другий тест для FCEDIT.
Єнс

1
Правильно. Зауважте, що posh(pdksh з видаленою більшістю функцій, що не є POSIX, тому ви, ймовірно, хочете назвати це "sh") не має FCEDIT, а також KSH_VERSION, але має PS3 (можливо, ненадовго), хоча навряд чи для одного він матиме його як оболонку входу . Також зверніть увагу , що наведений вище код не буде відображати bashабо zshв shрежимі емуляції, що може бути проблемою , якщо ви використовуєте , $PROFILE_SHELLщоб вирішити , слід включити ту чи іншу функцію. Ознайомтесь також із таблицею Sven Mascheck, яку ви можете (а може і не захочете) перевірити.
Стефан Шазелас

6

Ви можете спробувати

ps -o args= -p "$$"

яка дасть вам назву команди, пов'язаної з pid сценарію.


Наскільки я не можу сказати, це не працює при використанні шебангу. sprunge.us/QeHD
Chris Down

Вибачте, @ChrisDown, Flup. Моє погане, я неправильно переклав cmdна commколи POSIXifying відповідь.
Стефан Шазелас

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я отримую шлях до батьківського оболонки.
Тор

Зауважте, що POSIX shs мають $PPIDзмінну. Увімкнено Linux, ви можете використовувати readlink -f "/proc/$PPID/exe".
Стефан Шазелас

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 / тощо. відфільтруйте вихід, щоб отримати оболонку, на якій працює сценарій.

Отже, очищена вихідна версія (працює для 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" або якийсь нещасний греп-шаблон, який знищить інформацію. :) Буде потрібно певне налаштування для вашого власного оточення, щоб забезпечити більш високий ступінь дурмостійкості.


-2

Ви можете використовувати команду:

$ echo $SHELL

щоб дізнатися оболонку з сценарію.


18
Ні. $SHELL- оболонка за вибором користувача. Ініціалізований із оболонки входу користувача. Нічого спільного з поточно працюючою оболонкою.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.