Системный вызов exec
ядра Linux понимает шебанги (#!
) изначально
Когда вы делаете на Bash:
./something
в Linux, это вызывает системный вызов exec
с путем ./something
.
Эта строка ядра вызывается для файла, переданного exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm-> buf [0]! = '#') || (bprm-> buf [1]! = '!'))
Это читает самые первые байты файла и сравнивает их с #!
.
Если это так, то остальная часть строки анализируется ядром Linux, которое делает еще один вызов exec с путем /usr/bin/env python
и текущим файлом в качестве первого аргумента:
/usr/bin/env python /path/to/script.py
, и это работает для любого языка сценариев, который использует #
в качестве символа комментария.
И да, вы можете сделать бесконечный цикл с помощью:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash распознает ошибку:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
просто читается человеком, но это не обязательно.
Если файл начинается с разных байтов, то системный вызов exec
будет использовать другой обработчик. Другой наиболее важный встроенный обработчик для исполняемых файлов ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305, который проверяет байты 7f 45 4c 46
(который также может быть прочитан человеком для .ELF
). Это читает файл ELF, правильно помещает его в память и запускает новый процесс с ним. См. Также: Как ядро получает исполняемый двоичный файл, работающий под Linux?
Наконец, вы можете добавить свои собственные обработчики shebang с помощью механизма binfmt_misc
. Например, вы можете добавить пользовательский обработчик для .jar
файлов . Этот механизм даже поддерживает обработчики по расширению файла. Другое приложение - для прозрачного запуска исполняемых файлов другой архитектуры с QEMU .
Я не думаю, что POSIX указывает на шебанги: https://unix.stackexchange.com/a/346214/32558, хотя это упоминается в разделах обоснования и в форме "если исполняемые сценарии поддерживаются системой, что-то случиться». Однако MacOS и FreeBSD, похоже, также реализуют это.
PATH
поисковая мотивация
Вероятно, одной большой мотивацией для существования шебангов является тот факт, что в Linux мы часто хотим запускать команды из PATH
так же, как:
basename-of-command
вместо:
/full/path/to/basename-of-command
Но тогда, без механизма shebang, как Linux узнает, как запускать файлы каждого типа?
Жесткое кодирование расширения в командах:
basename-of-command.py
или реализация поиска PATH для каждого переводчика:
python basename-of-command
было бы возможным, но главная проблема в том, что все ломается, если мы когда-нибудь решим перевести команду на другой язык.
Шебанги прекрасно решают эту проблему.