В чем разница между выполнением Bash-скрипта и его поиском?
В чем разница между выполнением Bash-скрипта типа A и поиском Bash-скрипта типа B?
A
> ./myscript
B
> source myscript
Источник скрипт будет выполнять команды в процессе current shell.
Executing скрипт будет выполнять команды в процессе new shell.
Использовать исходный код, если вы хотите, чтобы скрипт изменил окружение в запущенной оболочке. Использовать выполнить по-другому.
Если вы все еще запутались, пожалуйста, прочтите дальше.
Чтобы прояснить некоторые распространенные путаницы с синтаксисом выполнения и синтаксисом исходного кода:
./myscript
Это будет исполняться myscript
при условии, что файл является исполняемым и расположен в текущем каталоге. Ведущая точка и косая черта (./
) обозначают текущую директорию. Это необходимо, потому что текущий каталог обычно не находится (и обычно не должен находиться) в $PATH
.
myscript
Это будет исполняться myscript
, если файл является исполняемым и расположен в какой-то директории в $PATH
.
source myscript
Это будет источник myscript
. Файл не обязательно должен быть исполняемым, но это должен быть корректный скрипт оболочки. Файл может быть в текущем каталоге или в каталоге $PATH
.
. myscript
Это также источник myscript
. Это “написание” является официальным, как определено в POSIX . Бэш определил 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
не установлена, и рабочий каталог не изменился.
Вывод скрипта четко показывает, что переменная была установлена, а каталог изменен. Проверка после этого показывает, что переменная не установлена и каталог не изменился. Что произошло? Изменения были сделаны в оболочке new. Оболочка current создала оболочку new для выполнения скрипта. Скрипт выполняется в новой оболочке, и все изменения в окружении вступают в силу в новой оболочке. После выполнения скрипта новая оболочка уничтожается. Все изменения окружения в новой оболочке уничтожаются в новой оболочке. В текущей оболочке распечатывается только выходной текст.
Теперь мы источник файла:
$ 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 установлена, а рабочий каталог изменился.
Источник скрипта не создает новую оболочку. Все команды выполняются в текущей оболочке, и изменения среды вступают в силу в текущей оболочке.
Обратите внимание, что в этом простом примере результат выполнения такой же, как и результат работы скрипта. Это не всегда так.
Рассмотрим следующий скрипт pid.sh
:
#!/bin/sh
echo $$
(специальная переменная $$
расширяется до PID текущего процесса выполнения оболочки)
Сначала распечатайте PID текущей оболочки:
$ echo $$
25009
Источник скрипта:
$ source pid.sh
25009
Выполнить сценарий, обратите внимание на PID:
$ ./pid.sh
25011
Источник снова:
$ source pid.sh
25009
Выполнить снова:
$ ./pid.sh
25013
Вы можете видеть, что поиск источников сценарий запускается в том же самом процессе во время выполнения сценария создает новый процесс каждый раз. Этим новым процессом является new shell, который был создан для выполнения скрипта. Источник скрипта не создает новую оболочку и, таким образом, PID остается прежним.
Как поиск, так и выполнение скрипта будут выполнять команды в скрипте построчно, как если бы вы набирали эти команды от руки построчно.
Разница в том, что:
Используйте исходный код, если вы хотите, чтобы скрипт изменил окружение в текущей оболочке. Используйте другое выполнение.
Смотрите также:
Выполнение скрипта запускает его в отдельном дочернем процессе, т.е. для обработки скрипта вызывается отдельный экземпляр оболочки. Это означает, что любые переменные окружения и т.д., определенные в скрипте _ не могут_ быть обновлены в родительском (текущем) shell'е.
Источник скрипта означает, что он анализируется и выполняется самой текущей оболочкой. Как будто вы набираете содержимое скрипта. По этой причине исходный скрипт не обязательно должен быть исполняемым. Но он должен быть исполняемым, если вы его выполняете.
Если у вас есть позиционные аргументы в текущей оболочке, они не изменяются.
Итак, если у меня есть файл a.sh
, содержащий:
echo a $*
, то у меня есть:
$ set `date`
$ source ./a.sh
Я получаю что-то вроде:
a Fri Dec 11 07:34:17 PST 2009
В то время как..:
$ set `date`
$ ./a.sh
дает мне:
a
Надежда, которая помогает.
Источник, по сути, тот же самый, что и ввод каждой строки скрипта в командной строке по одному в командной строке…
Execution запускает новый процесс, а затем запускает каждую строку скрипта, изменяя только текущее окружение тем, что оно возвращает.
Вы получаете все дополнительные переменные, определенные в скрипте.
Таким образом, если у вас есть конфигурации или определения функций, вы должны исходить и не выполнять. Выполнение не зависит от родительского окружения.
Команда source
выполняет предоставленный сценарий (разрешение на исполнение не обязательно ) в текущей оболочке, в то время как ./
выполняет предоставленный сценарий **executable в new оболочке. Также проверьте этот ответ, например,