Shell script работает отлично без линии shebang? Зачем?

Я писал простую оболочку script и обнаружил, что моя оболочка script не требует строки shebang

#!/bin/sh

Если я даю разрешения на выполнение для моего script и выполняю с помощью ./myscript.sh. Он отлично работает.

Я использую bash shell, а /bin/sh на самом деле указывает на bash.

lrwxrwxrwx 1 root root /bin/sh -> bash

Я знаю, что строка shebang используется, чтобы сообщить оболочке, какой интерпретатор использовать для вашего остального script.

Если я пропустил строку shebang в perl, дайте разрешения на выполнение и запустите ./myscript.pl, это не сработает.

Что на самом деле происходит здесь? Если я использую ./, когда действительно нужна строка shebang?

Ответ 1

требуется строка shebang в файле и только если она предназначена для запуска в качестве исполняемого файла (в отличие от sh file.sh invocation). На самом деле это не требуется script, это значит, что система знает, как найти интерпретатор.

РЕДАКТИРОВАТЬ: Извините за неправильное понимание вопроса. Если строка shebang отсутствует или не распознана, используется /bin/sh. Но я предпочитаю быть явным о интерпретаторе.

Обратите внимание, что это поведение не является универсальным, IIRC, только некоторые семейные функции exec* делают это (не говоря уже о разных платформах), так что здесь еще одна причина быть явной.

Ответ 2

Родительская оболочка, где вы вошли ./myscript.sh, первый попытался execve его, что где притон линия вступит в силу, если присутствует. Когда это работает, родитель не знает о разнице между скриптами и ELF, потому что ядро заботится об этом.

execve потерпел неудачу, поэтому была активирована древняя функция совместимости с Unix, предшествовавшая существованию линий shebang. Он предположил, что файл, который имеет разрешение на выполнение, но не распознается ядром как допустимый исполняемый файл, должен быть сценарием оболочки.

Обычно родительская оболочка предполагает, что сценарий написан для той же оболочки (минимальные оболочки типа Борна запускают сценарий с /bin/sh, bash запускает его как подпроцесс bash), csh делает более сложное предположение на основе первого символа потому что он предшествует Шебангу и должен был сосуществовать с оболочкой Борна).

Вам нужна строка shebang, когда вы знаете, что эти догадки будут неправильными (например, для shebang это #!/usr/bin/perl), или когда вы не доверяете предположениям для последовательной работы, или когда сценарий должен быть запускается родительским процессом, который не является самой оболочкой.

Ответ 3

Стандарт POSIX (Single UNIX Specification 4) не помогает:

Если первая строка файла команд оболочки начинается с символов "#!", результаты не указаны.

Итак, стандарт означает, что если у вас нет #! то он должен запустить оболочку POSIX. Но современные оболочки не совместимы с POSIX. Старый Korn Shell 88 (ksh88) управлял оболочкой Bourne (рядом с оболочкой POSIX) без #! line, но ksh93 ломается, и, таким образом, Bash. Как с ksh93, так и с Bash, они запускают свою собственную оболочку, если нет #! строка присутствует.

Несмотря на распространенное мнение, Bash и оболочки Korn отличаются. Когда вы пишете оболочку script, вы никогда не можете быть уверены в том, из какой оболочки вы будете работать, или даже если она будет запущена из другой оболочки вообще (большинство языков программирования могут запускать другие программы). В тот момент, когда вы используете что-то за пределами синтаксиса Bourne/POSIX, вы будете подвергнуты сомнению.

Всегда используйте #! линии, не оставляйте это на случай.