В чем разница между выполнением сценария Bash и его поиском?


Ответы:


346

Краткий ответ

Поиск сценария будет запускать команды в текущем процессе оболочки.

Выполнение скрипта запустит команды в новом процессе оболочки.

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

Если вы все еще не уверены, читайте дальше.

терминология

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

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

Резюме

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

Различия:

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

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


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


2
Одним из способов использования источников является создание элементарной формы файла конфигурации для ваших сценариев. Вы начинаете с того, что устанавливаете различные переменные в значения по умолчанию, а затем исходите из чего-то вроде myscript.conf - и этот исходный скрипт может иметь операторы присваивания, которые переопределяют любые значения, которые вы хотите. Поскольку исходный скрипт не начинается с # / bin / bash, его не рекомендуется выполнять напрямую.
LawrenceC

Таким образом, источник вроде как запускает его в глобальной области видимости, а выполнение создает новую локальную область видимости. Можно ли распространить это на функцию в скрипте? выполнить функцию (обычно) или «получить» ее?
aliteralmind

2
Есть ли разница между использованием source myscript.shи . myscript.sh?
Holloway

2
практически без разницы, если использовать Bash. source это псевдоним в bash.
Лесмана

1
Мне нравится, когда люди приводят такие сложные примеры, чтобы даже новички в Linux, такие как я, могли понять. Спасибо!
Джулиус

21

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

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

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

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

echo a $*

и я делаю:

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

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

a Fri Dec 11 07:34:17 PST 2009

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

$ set `date`
$ ./a.sh

дает мне:

a

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


5
хотя этот ответ верен во всех отношениях, мне очень трудно его понять, потому что он демонстрируется с использованием другой концепции (установка позиционных параметров), которая, на мой взгляд, еще более запутана, чем различие в поиске и выполнении самого себя.
Лесмана

9

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

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


6

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


2
Правда, но если это проблема, вы всегда можете запустить bash myscript.
Даниэль Бек

5

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


3

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


2

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.