Я запускаю простой исполняемый файл, который называется hello
в bash. Он запрашивает у пользователя ввод и выводит ответ. Я запускаю его так ./hello
.
И запрос, и ввод пользователем своего ответа происходят в текущей оболочке, но я думал, что это должно было быть запущено в другой оболочке. Я предположил это, потому что вы можете использовать источник для запуска exe в текущей оболочке.
Кто-нибудь может мне объяснить, как это работает?
Пытаясь исследовать это, я часто сталкивался с терминами «среда оболочки» и «контекст оболочки». Это одно и то же?
решение1
Вы можете сказать "shell environment" о среде текущей оболочки, которая включает текущие переменные среды. Среда наследуется любым запущенным подпроцессом (подоболочкой или иным).
Термин «контекст оболочки» используется нечасто, но я предполагаю, что он эквивалентен «контексту процесса». В случае скрипта оболочки это будет включать среду оболочки, а также текущие переменные оболочки, дескрипторы файлов (стандартный ввод, стандартный вывод и стандартная ошибка, а также любые другие явно открытые), обработчики сигналов (установленные с помощью trap
) и т. д. Если бы это была программа на языке C, контекст процесса был бы унаследован при вызове fork()
, но не при последующем exec()
вызове (только среда выживет при вызове exec()
).
Когда вы запускаете свою hello
программу, которая, как я предполагаю, является скриптом оболочки, ввод и вывод происходят в контексте оболочки, которая выполняет скрипт hello
. Это «текущая оболочка». Оболочка, в которую вы ввели данные, ./hello
является ее родительской оболочкой и hello
наследует ее окружение.
Внутри себя родительская оболочка выполняет вызов fork()
и exec()
запускает оболочку, которая в конечном итоге запустит hello
скрипт.
Тот факт, что hello
сценарий побуждает в том жеТерминалкак то, где вы запустили скрипт, просто означает, что оболочка, запускающая скрипт, является текущим процессом переднего плана там. Родительская оболочка ждет его завершения. Когда он завершится, родительская оболочка снова станет процессом переднего плана в терминале.
Когда вы запускаете скрипт с помощью source ./hello
или . ./hello
, скрипт выполняется в том же контексте, что и оболочка, в которую вы ввели эту команду. Это означает, что он может изменить контекст и среду интерактивной оболочки. Например, он может изменить текущий рабочий каталог (изменить среду) или установить обработчик сигналов (изменить контекст), и эти изменения будут по-прежнему «активны» после завершения выполнения скрипта.
Если hello
программа является скомпилированным двоичным файлом, она унаследует среду вызывающей оболочки, но не будет разделять ее контекст (файловые дескрипторы и т. д.). На самом деле она не работает в подоболочке, поскольку не является скриптом оболочки. Родительская оболочка перейдет в фоновый режим, ожидая завершения программы, как это было бы со скриптом оболочки. С точки зрения родительской оболочки нет никакой разницы между запуском скомпилированного двоичного файла или скрипта оболочки.
Скомпилированный двоичный файл нельзя начинать с символа source
или .
(точка), поскольку оболочка не знает, как интерпретировать двоичный файл.
В этом ответе есть немного размахивания руками, но я считаю, что в целом он правильный. Пожалуйста, оставьте комментарий (или отредактируйте), если что-то нужно исправить или добавить.