6.5Kпросмотров
7 июля 2024 г.
Score: 7.1K
Сидел я сегодня такой, развлекался с Nix'ом и внезапно обнаружил, что конструкции вида nix shell nixpkgs#hello -c bash в шебанге и Linux и MacOS отрабатывают совершенно по-разному. Краткая справка: Шебанг (shebang) - это конструкция вида #!interpreter [args] (#! обязателен), расположенная строго в начале файла, и говорящая операционной системе запустить interpreter [args] [original file] [original args].
Была придумана, чтобы не писать руками python script.py, а сделать ./script.py, условный. Когда функциональность уровня ядра ведет себя как-то неправильно, первое и логичное решение... пойти копаться в сорцах этого самого ядра. Спасибо эплу, некоторым лицензиям, и неизвестному самаритянину (насколько я знаю, это неофициальное зеркало) - у нас есть код XNU (ядро MacOS) на гитхабе. Непродолжительные поиски действительно привели меня к строке, в которой определяется условие конец шебанга, где концом строки считается либо #, либо \n.
Окей, теперь я знаю, что у меня нет шизофрении (на самом деле есть), и это действительно ядро ведет себя так странно.
Встает следующий вопрос: а почему оно так себя ведет? Если посмотреть на путь к файлу kern_exec.c, можно увидеть, что он начинается с папки bsd. Так возможно это не у apple что-то с головой, а они просто бэкпортировали какое-то странное изменение из ядра BSD? (Да, XNU основан во многом на BSD) Быстро пробежавшись по старым BSD ядрам (4.3BSD, FreeBSD версий 2-3) я ничего полезного не нашел, там этой особенности не было. Дальше я решил вернуться обратно к blame'у сорцов XNU. К сожалению, текстов коммитов нет (разве что где-то в недрах Apple), поэтому остается довольствовать описаниями версий, в которых что-то меняли.
Таким образом я узнал, что это добавили в XNU-517. Быстрый гуглеж по XNU-517 shebang наконец-то привел меня к цели всего поста: шедевральной страничке https://www.in-ulm.de/~mascheck/various/shebang/, содержащей огромный и очень информативный текст (я не шучу, сходите сами почитайте!) про историю шебангов. Конкретно про обработку второй # - тут.
Как оказалось, я смотрел слишком ранние версии FreeBSD - это действительно внесли именно в ней, в 4.0 ветке, а потом убрали в 6.0.
XNU бэкпортировали это к себе, но так и не убрали, только рефакторя код год за годом (стало кстати объективно лучше, тоже забавное наблюдение). Итак. Изначальной причиной появления такого способа обработки # в шебангах была...
Рекомендация в документации к perl'у писать шебанг следующим образом: #!/bin/sh -- # -- perl -- -p
чтобы избегать каких-то странных кроссплатформенных проблем (да, утилиту env тогда ещё не придумали). Зайдите ещё в комменты, там есть парочка мемов, которые не влезли в пост =)