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


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.