Как обнаружить командный интерпретатор из сценария оболочки? [дубликат]

Возможный дубликат:
Как проверить, какую оболочку я использую в терминале?

Я хочу определить, какой интерпретатор использует сценарий оболочки. Например, следующий скрипт:

  #!/Bin/bashissue_interpreter_name ()  

Должен показать интерпретатор:

bash 

8

  #!/bin/sh ps h -p $$ -o args = '' |  cut -f1 -d ''  
  • ps список процессов
  • h не печатать заголовки столбцов
  • -p выводить только PID идентификатора процесса
  • $$ заменяется оболочкой с текущим PID.
  • -o args выводит командную строку, никакой другой информации
  • разрезать нарезать вывод на части
  • -f1 напечатать только первое поле
  • -d '' использовать пробел в качестве разделителя полей

    $ ./testje

    /bin/sh

Улучшите этот ответ
отредактировано 3 мая ’12 в 18:55
ответил 3 мая ’12 в 18: 27
  • На Mac OX X я получаю дополнительную строку с заголовком ARGS . С помощью -o args = '' вы можете удалить заголовок — Маттео 3 мая 2012 г., 18:50
  • 1
    Подтвержденный комментарий Маттео для Linux (ubuntu 12.04) и работает как задумано. Обновил свой ответ. — jippie 3 мая ’12 в 18:55
добавить комментарий |

  #!/bin/sh ps h -p $$ -o args = '' |  cut -f1 -d ''  
  • ps список процессов
  • h не печатать заголовки столбцов
  • -p выводить только PID идентификатора процесса
  • $$ заменяется оболочкой с текущим PID
  • -o args выводит командную строку, никакой другой информации
  • разрезать нарезать вывод на части
  • -f1 распечатать только первое поле
  • -d '' использовать пробел в качестве разделителя полей

    $./testje

    /bin/sh


-1

Если это локальный пользователь, седьмое поле/etc/passwd является его оболочкой. Вы ищете оболочку, предпочитаемую в настоящее время?

Улучшите этот ответ
ответил 3 мая ’12 в 12:00
  • 2
    -1 Оболочка входа по умолчанию не обязательно должна быть запущенной в данный момент. — rahmu 3 мая ’12 в 12:05
добавить комментарий |

Если это локальный пользователь, седьмое поле/etc/passwd является их оболочкой. Вы ищете оболочку, предпочитаемую на данный момент?



Внутреннее устройство Linux: как работают сценарии интерпретатора

Сценарии оболочки — обычная тема в вопросах собеседования по Linux. Помимо овладения искусством создания сценариев Bash, полезно понять, как ядро ​​обрабатывает сценарий — любой сценарий интерпретатора — иначе, чем, скажем, обычный исполняемый файл ELF.

Сначала определения!

Сценарий — это исполняемый файл, который начинается со строки (начинающейся с символов #! ), указывающей путь к интерпретатору сценария.

#! /путь/к/интерпретатору [args]

В большинстве реализаций Unix пробел после #! является необязательным.

Как ядро ​​выполняет сценарий

Что происходит, когда вы выполняете сценарий Python, подобный этому?

   #!/usr/bin/pythonprint "Hello World"  

Если вы strace сценарий для перехвата системных вызовов, вы должны увидеть следующее:

  $ strace -e trace = open, execve, write ./ hello.pyexecve ("./hello.py", ["./hello.py"], [/* 59 vars */]) = 0open ("/etc/ld.so.cache", O_RDONLY | O_CLOEXEC) =  3open ("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY | O_CLOEXEC) = 3open ("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY | O_CLOEXEC) = 3open (  "/lib/x86_64-linux-gnu/libutil.so.1", O_RDONLY | O_CLOEXEC) = 3open ("/lib/x86_64-linux-gnu/libz.so.1", O_RDONLY | O_CLOEXEC) = 3open ("/ lib/x86_64-linux-gnu/libm.so.6 ", O_RDONLY | O_CLOEXEC) = 3open ("/lib/x86_64-linux-gnu/libc.so.6 ", O_RDONLY | O_CLOEXEC) = 3o  pen ("/usr/lib/python2.7/site.x86_64-linux-gnu.so", O_RDONLY) = -1 ENOENT (Нет такого файла или каталога) ... open ("./привет. py ", O_RDONLY) = 3write (1," Hello World  n ", 12Hello World) = 12 +++ завершено с 0 +++  

Существует ровно один вызов execve () с именем файла сценария в качестве первого аргумента: здесь не выполняется интерпретатор Python!

Что же происходит под thehoodis? ядро распознает такой исполняемый файл как сценарий интерпретатора, учитывая, что он начинается с магических чисел sha-bang ( 0x23 0x21 ). Вся первая строка файла затем разделяется на путь интерпретатора и (необязательно ) args. Интерпретатор находится в файловой системе и вызывается с помощью пути к сценарию в качестве первого аргумента.

В приведенном выше примере любой системный вызов после execve () на самом деле выдается двоичным файлом интерпретатора Python, хотя вы не можете напрямую видеть его выполнение.

Интерпретатор и аргументы сценария

Первая строка файла сценария определяет путь интерпретатора и необязательные аргументы для самого интерпретатора. Любой другой аргумент командной строки ument добавляется после пути к сценарию. Поясним это на примере:

  $ cat script.sh #!/Home/cristian/myecho interp_arg1 interp_arg2   

Интерпретатор myecho — это небольшая программа на C, которая выводит argv :

  #include  int main (int argc, char * argv []) {for (int i = 0; i % s  n", i, argv [i]);  }}  

При выполнении script.sh с дополнительными аргументами командной строки вывод будет:

  $ ./script.sh cli_arg1 cli_arg20 ->/home/cristian/myecho1 -> interp_arg1 interp_arg22 -> ./script.sh3 -> cli_arg14  -> cli_arg2  

Здесь вы видите, что внутри execve () аргументы перегруппированы следующим образом:

  интерпретатор-путь интерпретатор-аргументы скрипт-путь скрипт-аргументы  

В Linux аргументы интерпретатора анализируются как одна строка (это объясняет, почему interp_arg1 interp_arg2 печатаются как одна запись argv ), и это может быть источником проблем с переносимостью. Вы также должны знать, что в Linux общая длина первой строки сценария (т.е. sha-bang + интерпретатор-путь + интерпретатор-аргументы) не может быть длиннее 128 символов (включая новую строку).

Проблема с PATH

Путь интерпретатора обычно является абсолютным путем (хотя относительный путь все еще может использоваться). Фактически, механизм $ PATH вашей оболочки — это бессмысленное пространство ядра (помните, что все, что мы здесь обсуждаем, происходит внутри системного вызова execve () ). Путь к интерпретатору должен быть точным расположением исполняемого файла.

В целях переносимости утилита env (1) часто используется в качестве временного решения.. Предполагая, что env обычно устанавливается по стандартному пути /usr/bin/env , этот небольшой исполняемый файл затем используется как трамплин для запуска реального интерпретатора, который тогда он должен быть расположен где-нибудь в PATH пользователя.

  #!/usr/bin/env pythonprint "Hello World"  

Другими словами, #!/usr/bin/env python выполняет env в качестве интерпретатора, передавая python в качестве аргумента интерпретатора. Сам env обычно реализуется с помощью вызова execvp (3) — вызова библиотеки C — который ищет данный исполняемый файл в PATH.

Вложение интерпретатора

Некоторые реализации UNIX позволяют интерпретатору сценария быть ascript самому себе. В Linux этот вид «поиска исполняемых файлов» является рекурсивным с жестко заданным пределом в четыре рекурсии.

  $ cat nested.sh #!  ./nested.sh$ ./nested.shbash: ./nested.sh:/nested.sh: плохой интерпретатор: слишком много уровней символических ссылок  

Бит setuid игнорируется

В Linux и в других реализациях Unix бит setuid в скриптах игнорируется по соображениям безопасности.

Мы можем подготовить небольшую тестовую программу:

  #include  #include   int main () {printf ("real =% d effective =% d  n", getuid (), geteuid ());}  

Разрешение setuid для двоичного исполняемого файла работает должным образом:

  $ ./test-  setuidreal = 1000 эффективный = 1000 $ sudo chown root test-setuid && sudo chmod + s test-setuid $ ./test-setuidreal=1000 эффективный = 0  

Если мы проделаем то же самое со скриптом, бит setuid игнорируется вместо этого:

  $ cat test-setuid.sh #!/bin/bashid -u $ ./test-setuid.sh1000$  sudo chown root test-setuid.sh && sudo chmod + s test-setuid.sh $ ./test-setuid.sh1000

Дальнейшее чтение

В описании выше я несколько раз упомянул, что некоторые детали очень специфичны для Linux. Это связано с тем, что, к сожалению, механизм #! не является официально частью какой-либо спецификации Unix. Здесь описаны более подробные сведения о различиях между существующими Unixflavour и их развитии с течением времени.

Оцените статью
logicle.ru
Добавить комментарий