Яка різниця між виконанням сценарію Bash і джерелом його пошуку?


Відповіді:


344

Коротка відповідь

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

Виконання сценарію запустить команди в новому процесі оболонки.

Використовуйте джерело, якщо ви хочете, щоб сценарій змінив оточення в поточній запущеній оболонці. використовувати Execute інакше.

Якщо ви все ще плутаєтеся, читайте далі.

Термінологія

Щоб уточнити загальну плутанину щодо синтаксису для виконання та синтаксису до джерела:

./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не встановлена, а робочий каталог не змінювався.

Вихід сценарію чітко показує, що змінна була встановлена ​​і каталог змінено. Після цього перевірка показує, що змінна не встановлена ​​та каталог не змінений. Що трапилось? Зміни внесені в нову оболонку. Поточна оболонка породила нову оболонку для запуску сценарію. Сценарій працює в новій оболонці, і всі зміни в оточенні набувають чинності в новій оболонці. Після виконання сценарію нова оболонка знищується. Усі зміни середовища в новій оболонці знищуються з новою оболонкою. У поточній оболонці друкується лише вихідний текст.

Тепер ми джерело файлу:

$ 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

Ви можете бачити, що джерело пошуку сценарію працює в одному і тому ж процесі під час виконання сценарію щоразу створює новий процес. Цей новий процес - це нова оболонка, створена для виконання сценарію. Виділення скрипту не створює нової оболонки і, таким чином, PID залишається таким же.

Підсумок

Як джерело, так і виконання сценарію будуть виконувати команди в скрипті по рядку, як якщо б ви ввели ці команди вручну, рядок.

Відмінності:

  • Коли ви виконати скрипт , який ви відкриваєте нову оболонку, введіть команди в новій оболонці, скопіюйте вихід назад в поточну оболонку, а потім закрийте нову оболонку. Будь-які зміни в середовищі наберуть чинності лише в новій оболонці і втрачаються, коли нова оболонка буде закрита.
  • Коли ви джерело сценарію, ви вводите команди в поточну оболонку. Будь-які зміни в середовищі наберуть чинності і залишаться у вашій поточній оболонці.

Використовуйте джерело, якщо ви хочете, щоб сценарій змінив оточення в поточній запущеній оболонці. використовувати Execute інакше.


Дивитися також:


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

Таким чином, джерело подібний до запуску в глобальному масштабі, а виконання створює нову локальну область. Чи можна це поширити на функцію в сценарії? виконати функцію (як правило) або "джерело" її?
aliteralmind

2
Чи є різниця між використанням source myscript.shта . myscript.sh?
Холлоуей

2
практично немає різниці, якщо використовувати bash. Джерело є псевдонімом для крапки в bash.
lesmana

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
хоча ця відповідь є коректною в усіх відношеннях, мені важко зрозуміти, оскільки вона демонструється за допомогою іншої концепції (встановлення позиційних параметрів), яка, на мою думку, навіть більш заплутана, ніж різниця пошуку та виконання самого себе.
lesmana

9

пошук по суті такий же, як і введення кожного рядка сценарію в командному рядку по одному ...

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


6

На додаток до вище, виконання сценарію ./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.