Итак, я подумал, что хорошо понимаю это, но просто провел тест (в ответ на разговор, в котором я с кем-то не согласен) и обнаружил, что мое понимание неверно ...
Как можно более подробно, что именно происходит, когда я запускаю файл в моей оболочке? Что я имею в виду, если я ввожу : ./somefile some arguments
в свою оболочку и somefile
нажимаю return (и существует в cwd, и у меня есть разрешения на чтение + выполнение somefile
), то что происходит под капотом?
Я думал, что ответ был:
- Оболочка делает системный вызов
exec
, минуя путь кsomefile
- Ядро проверяет
somefile
и просматривает магический номер файла, чтобы определить, является ли этот формат обработчиком - Если магическое число указывает, что файл находится в формате, который процессор может выполнить, то
- создается новый процесс (с записью в таблице процессов)
somefile
читается / отображается в память Стек создается, и выполнение переходит к точке входа кодаsomefile
, сARGV
инициализированным массивом параметров (achar**
,["some","arguments"]
)
- Если магическое число представляет собой шебанг, то
exec()
запускается новый процесс, как указано выше, но используемый исполняемый файл является интерпретатором, на который ссылается шебанг (например,/bin/bash
или/bin/perl
), иsomefile
передаетсяSTDIN
- Если в файле нет действительного магического номера, возникает ошибка типа «неверный файл (неправильное магическое число): ошибка формата Exec»
Однако кто-то сказал мне, что если файл представляет собой простой текст, то оболочка пытается выполнить команды (как будто я набрал bash somefile
). Я не верил в это, но я просто попробовал, и это было правильно. Поэтому у меня явно есть некоторые неправильные представления о том, что на самом деле здесь происходит, и я хотел бы понять механику.
Что именно происходит, когда я запускаю файл в моей оболочке? (насколько подробно это разумно ...)
source somefile
очень сильно отличается от нового процесса, который был отменен./somefile
../somefile
это приведет к тому, что bash выполнит команды,somefile
если в файле нет магического числа. Я думал, что это просто отобразит ошибку, и вместо этого, по-видимому, эффективноsource somefile
somefile
текстовый файл, то новая оболочка появляется, если я пытаюсь выполнить его. Файлecho $$
ведет себя по-разному, если я выполняю его против исходного кода.Ответы:
Окончательный ответ на вопрос «как программы запускаются» в Linux - это пара статей на LWN.net , которые, как ни удивительно, озаглавлены « Как программы запускаются и как программы запускаются: двоичные файлы ELF» . В первой статье кратко рассматриваются сценарии. (Строго говоря, окончательный ответ содержится в исходном коде, но эти статьи легче читать и содержат ссылки на исходный код.)
Небольшой эксперимент показывает, что вы в значительной степени поняли это правильно, и что оболочка должна обрабатывать выполнение файла, содержащего простой список команд без шебанга. Страница руководства execve (2) содержит исходный код тестовой программы execve; мы будем использовать это, чтобы увидеть, что происходит без оболочки. Сначала напишите тестовый скрипт
testscr1
, содержащийи еще один
testscr2
, содержащий толькоСделайте их обоих исполняемыми и убедитесь, что они оба запускаются из оболочки:
Теперь попробуйте снова, используя
execve
(при условии, что вы создали его в текущем каталоге):testscr1
все еще работает, ноtestscr2
производитЭто показывает, что оболочка обрабатывает по-
testscr2
разному. Он не обрабатывает сам скрипт, хотя он все еще использует/bin/sh
для этого; это можно проверить по конвейеруtestscr2
кless
:В моей системе я получаю
Как видите, есть оболочка, которую я использовал,
zsh
которая запустиласьless
, и вторая оболочка, простаяsh
(dash
в моей системе), для запуска сценария, который запустилсяpstree
. Вzsh
этом обрабатываетсяzexecve
вSrc/exec.c
: Оболочка использует ,execve(2)
чтобы попытаться выполнить команду, и если это не удается, он читает файл , чтобы увидеть , если он имеет хижину, обрабатывая его соответствующим образом (что ядро будет также сделано), и если это терпит неудачу, он пытается запустить файлsh
, если он не прочитал ни одного нулевого байта из файла:bash
имеет такое же поведение, реализованноеexecute_cmd.c
с помощью полезного комментария (как указал талиезин ):POSIX определяет набор функций, известный как в
exec(3)
функции , которая обертываниеexecve(2)
и обеспечить эту функциональность тоже; подробности смотрите в ответе Муру . В Linux по крайней мере эти функции реализуются библиотекой C, а не ядром.источник
Частично это зависит от конкретной
exec
функции семьи, которая используется.execve
Как подробно показал Стивен Китт , файлы запускаются только в правильном двоичном формате или сценарии, которые начинаются с правильного шебанга.Однако ,
execlp
иexecvp
сделайте еще один шаг: если шебанг был неверным, файл выполняется/bin/sh
в Linux. Отman 3 exec
:Это в некоторой степени поддерживается POSIX (выделено мое):
Это не определяет, как получается интерпретатор команд, но не указывает, что должна быть выдана ошибка. Поэтому я предполагаю, что разработчики Linux позволяли запускать такие файлы с
/bin/sh
(или это уже было обычной практикой, и они просто следовали этому примеру).FWIW, страница
exec(3)
руководства FreeBSD для также упоминает похожее поведение:AFAICT, однако, не использует обычную оболочку
execlp
илиexecvp
напрямую, предположительно для более точного контроля над окружающей средой. Все они используют одну и ту же логикуexecve
.источник
execl
,execlp
,execle
,execv
,execvp
иexecvpe
все передние концы к системномуexecve
вызову; первые предоставляются библиотекой C, о которой ядро знает толькоexecve
(и вexecveat
настоящее время).Это может быть дополнение к ответу Стивена Китта, как комментарий от
bash
источника в файлеexecute_cmd.c
:источник
Он выполняется как сценарий оболочки, он не является источником (например, переменные, установленные в исполняемом файле, не влияют снаружи). Вероятно, рудимент из туманного прошлого, когда была одна оболочка и один исполняемый формат. Не исполняемый файл, это должен быть скрипт оболочки.
источник
exec()
или оболочка? Я хочу значительно больше внутренних