245

В чем разница между выполнением Bash-скрипта типа A и поиском Bash-скрипта типа B?

A
> ./myscript

B
> source myscript

7 ответов7

307

Краткий ответ: источники будут запускать команды в текущем процессе оболочки. выполнение запустит команды в новом процессе оболочки. все еще в замешательстве? тогда, пожалуйста, продолжайте читать длинный ответ.

Терминология:

Чтобы прояснить некоторую путаницу в отношении синтаксиса для выполнения и синтаксиса для источника:

./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 остается прежним.

Резюме

И выполнение, и выполнение скрипта будут запускать команды в скрипте построчно, как если бы вы вводили эти команды вручную построчно.

Различия:

  • Когда вы выполняете скрипт, который вы открываете новую оболочку, введите команды в новой оболочке, скопируйте вывод обратно в вашу текущую оболочку и закройте новую оболочку. Любые изменения в среде вступят в силу только в новой оболочке и будут потеряны после закрытия новой оболочки.
  • Когда вы источник скрипта , который вы набираете команды в текущей оболочке. Любые изменения в среде вступят в силу и останутся в вашей текущей оболочке.

Используйте исходный код, если вы хотите, чтобы скрипт изменил среду в текущей запущенной оболочке. используйте выполнить иначе.


Смотрите также:

21

Выполнение сценария запускает его в отдельном дочернем процессе, т. Е. Для обработки сценария вызывается отдельный экземпляр оболочки. Это означает, что любые переменные среды и т.д., Определенные в сценарии, не могут быть обновлены в родительской (текущей) оболочке.

Выбор сценария означает, что он анализируется и выполняется самой текущей оболочкой. Это как если бы вы набрали содержимое скрипта. По этой причине исходный скрипт не обязательно должен быть исполняемым. Но он должен быть исполняемым, если вы выполняете его, конечно.

Если у вас есть позиционные аргументы в текущей оболочке, они не изменяются.

Так что, если у меня есть файл a.sh содержащий:

echo a $*

и я делаю:

$ set `date`
$ source ./a.sh

Я получаю что-то вроде:

a Fri Dec 11 07:34:17 PST 2009

В то время как:

$ set `date`
$ ./a.sh

дает мне:

a

Надеюсь, это поможет.

7

sourcing - это то же самое, что вводить каждую строку скрипта в командной строке по одному ...

Выполнение запускает новый процесс, а затем запускает каждую строку сценария, изменяя только текущую среду в зависимости от того, что он возвращает.

4

В дополнение к вышесказанному, выполнение сценария как ./myscript требует разрешения на выполнение для файла myscript, в то время как поиск не требует разрешения на выполнение. Вот почему chmod +x myscript не требуется перед source myscript

4

В качестве источника вы получите все дополнительные переменные, определенные в скрипте.
Поэтому, если у вас есть конфиги или определения функций, вы должны исходить, а не выполняться. Казни не зависят от родительской среды.

3

Если я правильно помню, выполнение скрипта запускает исполняемый файл в #! строка с файлом сценария в качестве аргумента (как правило, запускается новая оболочка и эффективно добавляется сценарий в новую оболочку, как с #!/bin/sh);
тогда как поиск сценария выполняет каждую строку в текущей среде оболочки, что полезно для изменения текущей оболочки (например, предоставления способа определения функций оболочки и экспорта переменных среды).

2

Команда source выполняет предоставленный сценарий (разрешение на выполнение не обязательно) в текущей среде оболочки, а ./ выполняет предоставленный исполняемый сценарий в новой оболочке.

Также, проверьте этот ответ, например: https://superuser.com/a/894748/432100

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .