Есть ли разница между "." а "источник" в bash, в конце концов?
Я искал разницу между "." и встроенные команды "source" и несколько источников (например, в этом обсуждении и на странице руководства bash) предполагают, что они одинаковы.
Однако после проблемы с переменными среды я провел тест. Я создал файл testenv.sh
который содержит:
#!/bin/bash
echo $MY_VAR
В командной строке я выполнил следующее:
> chmod +x testenv.sh
> MY_VAR=12345
> ./testenv.sh
> source testenv.sh
12345
> MY_VAR=12345 ./testenv.sh
12345
[обратите внимание, что первая форма вернула пустую строку]
Итак, этот небольшой эксперимент предполагает, что в конце концов есть разница, где для команды "source" дочерняя среда наследует все переменные от родительской, а для "." Это не.
Я что-то упустил, или это недокументированная / устаревшая особенность bash?
[GNU bash, версия 4.1.5(1)-релиз (x86_64-pc-linux-gnu) ]
2 ответа
Короткий ответ
В вашем вопросе вторая команда не использует ни .
оболочка встроенная ни source
встроенный. Вместо этого вы фактически запускаете скрипт в отдельной оболочке, вызывая его по имени (как и любой другой исполняемый файл). Это дает ему отдельный набор переменных среды (хотя, если вы экспортируете переменную среды в ее родительскую оболочку, она будет включена). Если вы измените /
в пространство, то это будет работать с .
встроенный, что эквивалентно source
,
Расширенное объяснение
Это синтаксис source
встроенная оболочка, которая выполняет содержимое скрипта в текущей оболочке (и, следовательно, с переменными среды текущей оболочки):
source testenv.sh
Это синтаксис .
встроенный, который делает то же самое, что и source
:
. testenv.sh
Однако этот синтаксис запускает скрипт как исполняемый файл и запускает новую оболочку для его запуска:
./testenv.sh
Это не с помощью .
встроенный. Скорее, .
является частью пути к файлу, который вы выполняете. Вообще говоря, вы можете запустить любой исполняемый файл в оболочке, вызвав его с именем, которое содержит хотя бы один /
персонаж. Чтобы запустить файл в текущем каталоге, предшествуя ему ./
Таким образом, это самый простой способ. Если текущий каталог не находится в вашем PATH
, вы не можете запустить скрипт с помощью команды testenv.sh
, Это сделано для того, чтобы люди не могли случайно выполнить файлы в текущем каталоге, когда они намереваются выполнить системную команду или какой-либо другой файл, который существует в каком-либо каталоге, указанном в PATH
переменная окружения.
Так как запуск файла по имени (а не с source
или же .
) запускает его в новой оболочке, он будет иметь свой собственный набор переменных окружения. Переменные среды наследуются от переменных среды вызывающего процесса (который в данном случае является вашей интерактивной оболочкой). Однако для передачи переменной среды в новую оболочку должно иметь место одно из следующих действий:
Переменная среды была экспортирована. Использовать
export
Оболочка встроенная для этого. В вашем примере вы можете использоватьexport MY_VAR=12345
установить и экспортировать переменную за один шаг, или, если она уже установлена, вы можете просто использоватьexport MY_VAR
,Переменная окружения явно установлена и передана для команды, которую вы запускаете. Обычно это достигается тем, что:
MY_VAR=12345 ./testenv.sh
./
Синтаксис для сценариев требует, чтобы работала строка Hashbang (правильно)
Кстати, обратите внимание, что, когда вы вызываете исполняемый файл по имени, как указано выше (а не с .
или же source
встроенные модули оболочки), то, какая программа оболочки используется для ее запуска, обычно не определяется тем, из какой оболочки вы ее запускаете. Вместо:
Для двоичных файлов ядро может быть настроено для запуска файлов этого конкретного типа. Он проверяет первые два байта файла на "магическое число", которое указывает, какой это двоичный исполняемый файл. Вот как исполняемые двоичные файлы могут работать.
Это, конечно, чрезвычайно важно, потому что скрипт не может работать без оболочки или другого интерпретатора, который является исполняемым двоичным файлом! Кроме того, многие команды и приложения являются скомпилированными двоичными файлами, а не скриптами.
(
#!
текстовое представление "магического числа", обозначающее текстовый исполняемый файл.)Для файлов, которые должны работать в оболочке или другом интерпретируемом языке, первая строка выглядит следующим образом:
#!/bin/sh
/bin/sh
может быть заменено любой другой оболочкой или интерпретатором, предназначенным для запуска программы. Например, программа на Python может начинаться со строки:#!/usr/bin/python
Эти строки называются hashbang, shebang и рядом других похожих имен. Посмотрите эту запись FOLDOC, эту статью в Википедии и прочитал ли интерпретатор #!/ Bin/sh? для дополнительной информации.
Если текстовый файл помечен как исполняемый, и вы запускаете его из своей оболочки (например,
./filename
) но это не начинается с#!
ядро не может его выполнить. Однако, увидев, что это произошло, ваша оболочка попытается запустить ее, передав ее имя некоторой оболочке. К какой это оболочке предъявляется несколько требований ("оболочка должна выполнить команду, эквивалентную запуску оболочки..."). На практике некоторые снаряды - в том числеbash
* - запустить другой экземпляр себя, в то время как другие используют/bin/sh
, Я настоятельно рекомендую вам избежать этого и использовать вместо этого строку hashbang (или запустить скрипт, передав его нужному интерпретатору, например,bash filename
).* Руководство по GNU Bash, 3.7.2 Поиск и выполнение команд: "Если это выполнение завершится неудачно, потому что файл не в исполняемом формате, и файл не является каталогом, предполагается, что это сценарий оболочки, а оболочка выполняет его, как описано в сценариях оболочки".
Да, ты что-то упустил.
Я думаю, что вы путаете '.' это означает текущий каталог, как в ./testenv.sh
и "." это означает source
(которая является встроенной командой). Так и в случае, когда "." средства source
это было бы . ./testenv.sh
, Есть смысл?
Так что попробуйте это:
MY_VAR=12345
. ./testenv.sh