Почему бы не использовать безупречные шебанги?

24

Возможно ли иметь шебанг, который вместо указания пути к интерпретатору имеет имя интерпретатора и позволяет оболочке найти его через $ PATH?

Если нет, то есть ли причина?

Амелио Васкес-Рейна
источник

Ответы:

20

Поиск в PATH является функцией стандартной библиотеки C в пользовательском пространстве, как и переменные среды в целом. Ядро не видит переменные окружения, за исключением случаев, когда оно переходит из окружения от вызывающего execveк новому процессу.

Ядро не выполняет никакой интерпретации пути в execve(это зависит от функций-оболочек, таких как execvpвыполнение поиска в PATH) или в шебанге (который более или менее перенаправляет execveвызов внутри). Так что вам нужно поставить абсолютный путь в шебанге. Оригинальная реализация притон была всего лишь несколько строк кода, и он не был значительно расширен с тех пор.

В первых версиях Unix оболочка вызывала себя сама, когда замечала, что вы запускаете скрипт. Шебанг был добавлен в ядро ​​по нескольким причинам (резюмируя обоснование Денниса Ричи :

  • Вызывающему не нужно беспокоиться, является ли выполняемая программа сценарием оболочки или собственным двоичным файлом.
  • Сам скрипт указывает, какой интерпретатор использовать вместо вызывающего.
  • Ядро использует имя скрипта в логах.

Шебанги без путей потребовали бы либо дополнить ядро ​​для доступа к переменным и процессам среды PATH, либо чтобы ядро ​​выполнило программу пользовательского пространства, которая выполняет поиск по PATH. Первый метод требует добавления непропорциональной сложности ядра. Второй способ уже возможен с #!/usr/bin/envШебанг .

¹ Если вы укажете относительный путь, он будет интерпретирован относительно текущего каталога процесса (а не каталога, содержащего скрипт), что вряд ли полезно в шебанге.

Жиль "ТАК - перестань быть злым"
источник
2
Нет, ядро ​​не требует абсолютного пути execveни в шебанге, хотя не имеет смысла иметь относительный путь в шебанге.
Стефан Шазелас
3
Для всех, кому интересно, как «shebang перенаправляет внутренний вызов execve»: ​​на самом деле это часть общего механизма запуска интерпретаторов на исполняемых файлах, которые в них нуждаются. Динамически связанные исполняемые файлы ELF «интерпретируются» /lib64/ld-linux-x86-64.so.2(см. lddВывод). Linux делает его полностью универсальным: binfmtподдержка (начиная с 2.1.43) позволяет регистрировать пары интерпретатор-путь / магическое число или расширение файла. Вы можете .exeвызывать PE32 wineпри их запуске, вызывать классы Java и файлы jar javaи т. Д. И т. Д.
Питер Кордес,
#! / usr / bin / env -S [shebang] был необходим для того, чтобы я запустил узел, не зная его пути (используя nvm - который размещает его в другом месте, чем я изначально ожидал).
TamusJRoyce
-S доступен только с coreutils 8.30. См. Gitlab.com/gnuwget/wget/commit/… .
Тим Рюхсен Rockdaboot
19

Там происходит больше, чем кажется на первый взгляд. #!строки интерпретируются ядром Unix или Linux, #!не является аспектом оболочек. Это означает, что на PATHсамом деле не существует в то время, когда ядро ​​решает, что выполнять.

Наиболее распространенный способ справиться с незнанием того, какой исполняемый файл запустить, или вызвать perlпереносным способом или подобным, - это использовать #!/usr/bin/env perl. Выполняется ядро /usr/bin/env, которое наследует PATHпеременную окружения. envНаходки (в данном примере) perlв PATHи использует execve(2)системный вызов , чтобы получить ядро для запуска perlисполняемого файла.

Брюс Эдигер
источник
4
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0

Преобразование в полный путь выполняется с помощью оболочки (более общего: в пользовательском пространстве). Ядро ожидает имя файла / путь, к которому оно может получить прямой доступ.

Если вы хотите, чтобы система нашла ваш исполняемый файл, просмотрев переменную PATH, вы можете переписать свой shebang как #!/usr/bin/env EXEC.

Но и в этом случае поиск выполняет не ядро.

Хауке Лагинг
источник
1
Преобразование в полный путь выполняется с помощью оболочки. Спасибо, хотя ... пример должен иллюстрировать это? На мой взгляд, оболочка только что запущена strace(преобразована /usr/bin/straceв какой-то момент) с 2 аргументами.
Алоис Махдал