В чем разница между выполнением Bash-скрипта типа A и поиском Bash-скрипта типа B?
A
> ./myscript
B
> source myscript
Краткий ответ: источники будут запускать команды в текущем процессе оболочки. выполнение запустит команды в новом процессе оболочки. все еще в замешательстве? тогда, пожалуйста, продолжайте читать длинный ответ.
Чтобы прояснить некоторую путаницу в отношении синтаксиса для выполнения и синтаксиса для источника:
./myscript
Выполните myscript
при условии, что файл является исполняемым и находится в текущем каталоге. Косая черта (./
) обозначает текущий каталог. Это необходимо, потому что текущий каталог обычно не находится в $PATH
.
myscript
Выполните myscript
если файл является исполняемым и находится в некотором каталоге в $PATH
.
source myscript
Источник myscript
. файл не обязательно должен быть исполняемым, но это должен быть допустимый скрипт оболочки. Файл может находиться в текущем каталоге или в каталоге в $PATH
.
. myscript
Источник myscript
. Этот синтаксис определяется POSIX . Bash определил source
как псевдоним команды точка.
Рассмотрим myscript.sh
со следующим содержимым:
#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD
Прежде чем выполнить скрипт, мы сначала проверяем текущую среду:
$ env | grep FOO
$ echo $PWD
/home/lesmana
Переменная FOO
не определена, и мы находимся в домашнем каталоге.
Теперь мы выполняем файл:
$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
Проверьте среду еще раз:
$ env | grep FOO
$ echo $PWD
/home/lesmana
Переменная FOO
не установлена и рабочий каталог не изменился.
Вывод скрипта ясно показывает, что переменная была установлена, а каталог был изменен. Проверка впоследствии показывает, что переменная не установлена и каталог не изменен. Что случилось? Изменения были сделаны в новой оболочке. Текущая оболочка породила новую оболочку для запуска сценария. Сценарий выполняется в новой оболочке, и все изменения в среде вступают в силу в новой оболочке. После выполнения скрипта новая оболочка уничтожается. Все изменения среды в новой оболочке уничтожаются новой оболочкой. Только выводимый текст печатается в текущей оболочке.
Теперь мы поставляем файл:
$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
Проверьте среду еще раз:
$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir
Переменная FOO установлена и рабочий каталог изменился.
Sourcing скрипт не создает новую оболочку. Все команды выполняются в текущей оболочке, а изменения в среде вступают в силу в текущей оболочке.
Обратите внимание, что в этом простом примере результат выполнения аналогичен поиску сценария. Это не всегда так.
Рассмотрим следующий скрипт pid.sh
:
#!/bin/sh
echo $$
(специальная переменная $$
расширяется до PID текущего запущенного процесса оболочки)
Сначала выведите PID текущей оболочки:
$ echo $$
25009
Исходный скрипт:
$ source pid.sh
25009
Выполните скрипт, запишите PID:
$ ./pid.sh
25011
Источник снова:
$ source pid.sh
25009
Выполните снова:
$ ./pid.sh
25013
Вы можете видеть, что использование сценария выполняется в одном и том же процессе, а выполнение сценария каждый раз создает новый процесс. Этот новый процесс - новая оболочка, которая была создана для выполнения скрипта. Выбор сценария не создает новую оболочку, поэтому PID остается прежним.
И выполнение, и выполнение скрипта будут запускать команды в скрипте построчно, как если бы вы вводили эти команды вручную построчно.
Различия:
Используйте исходный код, если вы хотите, чтобы скрипт изменил среду в текущей запущенной оболочке. используйте выполнить иначе.
Смотрите также:
Выполнение сценария запускает его в отдельном дочернем процессе, т. Е. Для обработки сценария вызывается отдельный экземпляр оболочки. Это означает, что любые переменные среды и т.д., Определенные в сценарии, не могут быть обновлены в родительской (текущей) оболочке.
Выбор сценария означает, что он анализируется и выполняется самой текущей оболочкой. Это как если бы вы набрали содержимое скрипта. По этой причине исходный скрипт не обязательно должен быть исполняемым. Но он должен быть исполняемым, если вы выполняете его, конечно.
Если у вас есть позиционные аргументы в текущей оболочке, они не изменяются.
Так что, если у меня есть файл a.sh
содержащий:
echo a $*
и я делаю:
$ set `date`
$ source ./a.sh
Я получаю что-то вроде:
a Fri Dec 11 07:34:17 PST 2009
В то время как:
$ set `date`
$ ./a.sh
дает мне:
a
Надеюсь, это поможет.
sourcing - это то же самое, что вводить каждую строку скрипта в командной строке по одному ...
Выполнение запускает новый процесс, а затем запускает каждую строку сценария, изменяя только текущую среду в зависимости от того, что он возвращает.
В дополнение к вышесказанному, выполнение сценария как ./myscript
требует разрешения на выполнение для файла myscript, в то время как поиск не требует разрешения на выполнение. Вот почему chmod +x myscript
не требуется перед source myscript
В качестве источника вы получите все дополнительные переменные, определенные в скрипте.
Поэтому, если у вас есть конфиги или определения функций, вы должны исходить, а не выполняться. Казни не зависят от родительской среды.
Если я правильно помню, выполнение скрипта запускает исполняемый файл в #!
строка с файлом сценария в качестве аргумента (как правило, запускается новая оболочка и эффективно добавляется сценарий в новую оболочку, как с #!/bin/sh
);
тогда как поиск сценария выполняет каждую строку в текущей среде оболочки, что полезно для изменения текущей оболочки (например, предоставления способа определения функций оболочки и экспорта переменных среды).
Команда source
выполняет предоставленный сценарий (разрешение на выполнение не обязательно) в текущей среде оболочки, а ./
выполняет предоставленный исполняемый сценарий в новой оболочке.
Также, проверьте этот ответ, например: https://superuser.com/a/894748/432100