Я читаю книгу "Командная строка Linux и Библия сценариев оболочки"3-е издание. На странице 279 я цитирую:
"Подстановка команд создает то, что называется
subshell
для запуска прилагаемой команды. Подоболочка - это отдельная дочерняя оболочка, созданная из оболочки, в которой выполняется сценарий. По этой причине любые переменные, которые вы создаете в сценарии, недоступны для команды подоболочки.Подоболочки также создаются, если вы запускаете команду из командной строки с помощью
./
path, но они не будут созданы, если вы просто запустите команду без пути ".
Последнее предложение меня смущает. Я тестировал простой скрипт, который экспортирует некоторые переменные; переменные не будут существовать после того, как скрипт существует, однако скрипт вызывается из ./
путь, или поместите скрипт в /usr/bin
и запустить его без пути. Мне кажется, что нет никакой разницы, как он вызывается относительно подоболочки.
Что я пропустил?
«Подстановка команд создает так называемую подоболочку для выполнения вложенной команды. Подоболочка - это отдельная дочерняя оболочка, созданная из оболочки, которая запускает сценарий.
Речь идет о таких конструкциях, как:
echo "$(date) `uname -r`"
В этом примере я вызываю две подоболочки, используя две разные поддерживаемые нотации для подоболочек. Первая подоболочка запускает date
команда, а вторая подоболочка запускает uname
команда. В echo
Команда выполняется исходной оболочкой после завершения работы обеих подоболочек.
По этой причине любые переменные, которые вы создаете в сценарии, недоступны для команды подоболочки.
Здесь автор получил задом наперед. Переменные, созданные до вызова подоболочки, доступны для подоболочки. Переменные, созданные внутри подоболочки, доступны только для подоболочки и исчезнут после завершения работы подоболочки.
Подоболочки также создаются, если вы запускаете команду из командной строки с использованием пути ./, но они не создаются, если вы просто запускаете команду без пути ».
Очень непонятно, что здесь пытается сказать автор. Если вы вызываете внешнюю команду, произойдет следующее, независимо от того, вызывается она с путем или без него:
fork
s, чтобы создать новый процесс.Это новый процесс, поэтому любые переменные, установленные внешней командой, будут недоступны для родительского процесса, как если бы это была подоболочка.
Автор мог иметь в виду один из следующих трех сценариев:
#!
строка в начале скрипта.)read
, который синтаксически выглядит как внешняя команда, найденная путем поиска PATH
. Но даже если синтаксически он выглядит одинаково, он будет вести себя по-другому. поскольку read
установит переменную, предназначенную для использования следующими командами, read
сам должен произойти в текущем процессе без каких-либо fork
вызов. (Даже внутренние команды, которые можно безопасно вызывать как подпроцесс, лучше выполнять в текущем процессе по соображениям производительности. Вызов fork
вроде дорого.). file
или source file
. В таком случае file
это не сценарий, но он чем-то похож. Все команды в file
будет вызываться текущей оболочкой без предварительного вызова fork
. (Но, конечно, команды внутри file
может вызвать fork
звонки). В этом случае любой #!
линия в file
будут игнорироваться, и любые переменные, установленные file
будет доступен для вашей текущей оболочки.