Яка різниця між запуском "bash script.sh" та "./script.sh"?


42

Якщо script.sh просто щось типове

#!/bin/bash
echo "Hello World!"

Чи є кращий спосіб запуску сценарію? Я думаю, спочатку потрібно chmod це, щоб він став виконуваним?

Відповіді:


56

Для вашого конкретного сценарію будь-який спосіб буде працювати, за винятком того, що ./script.shвимагає виконання та читання бітів, тоді bash script.shяк потрібен лише біт для читання.


Причина різниці вимог дозволів полягає в тому, як завантажується програма, що інтерпретує ваш сценарій:

  • ./script.sh змушує вашу оболонку запустити файл так, ніби це був звичайний виконуваний файл.

Оболонка розкручується і використовує системний виклик (наприклад execve), щоб змусити операційну систему виконувати файл у роздвоєному процесі. Операційна система перевірить права доступу до файлу (отже, слід встановити біт виконання) та передасть запит на завантажувач програми , який розглядає файл та визначає спосіб його виконання. У Linux компільовані виконувані файли починаються з магічного числа ELF , а сценарії починаються з #!( хешбанг ). Заголовок хешбангу означає, що файл є скриптом і його слід інтерпретувати програмою, яка вказана після хешбангу. Це дозволяє самому сценарію розповісти системі, як інтерпретувати сценарій.

З вашим сценарієм завантажувач програми виконає /bin/bashі передасть ./script.sh як аргумент командного рядка.

  • bash script.shзмушує вашу оболонку запускатися bashта передаватися script.shяк аргумент командного рядка

Так операційна система завантажиться bash(навіть не дивлячись script.sh, тому що це лише аргумент командного рядка). Потім створений bashпроцес інтерпретуватиме те, script.shщо він передається як аргумент командного рядка. Оскільки script.shвін читається лише bashяк звичайний файл, біт виконання не потрібно.


Я рекомендую використовувати, ./script.shхоча ви можете не знати, який інтерпретатор вимагає сценарію. Тож дозвольте завантажувачу програми визначити це для вас.


3
Якщо виконуваний біт не встановлений, ви можете також запустити скрипт, виконавши «./script.sh.»
Собака їсть котячий світ

1
@Dog Ви маєте рацію. Крапка - це ярлик для вбудованої команди 'source', яка запускає скрипт у поточному процесі bash. Отже, потрібен лише читабельний біт.
SkyDan

5
@Dogeatcatworld, хоча це правда, біг . ./script.sh- це не те саме, що bash script.sh(або ./script.sh. Розглянемо сценарій #!/usr/bin/python -V<newline> print test.
casey

12
Остерігайтеся, що пошук сценарію може призвести до забруднення інтерактивної сесії. Наприклад, якщо сценарій змінить змінну середовища PATH, ця зміна вплине на команди, що виконуються за джерелом. Цей підхід дійсно повинен бути зарезервований у ситуаціях, коли ви залежите від побічних ефектів (сценарії налаштування середовища тощо). Для інших ситуацій, коли ви не можете змінити дозволи, запуск команди в рядку shebang, дотримуючись імені сценарію, є найбезпечнішим підходом.
ctt

6
Зауважте, що якщо ви джерело сценарію в поточному каталозі, вам не потрібно використовувати ./ ; просто скажи . script.sh. Але я погоджуюся з людьми, які .не дозволяють використовувати команду для скриптів, які не мали на меті викликати таким чином. Я здивований, що ніхто не згадував, що якщо скрипт містить exitкоманди, і ви його джерелом, він може вийти з системи. Менш гострою проблемою буде, якщо сценарій робить a cd, оскільки це також вплине на батьківську (інтерактивну) оболонку.
Скотт

18

bash script.shвикликає сценарій безпосередньо за допомогою bash.
./script.shвикористовує шебанг #!/bin/bashдля визначення способу виконання.

Якщо ви дійсно хочете знати, який двійковий файл виконується, якщо ви це робите, bash script.shви могли б дізнатися which bash.

Тож у вашому прикладі це не має значення. Так, ви повинні chmod +x script.shмати можливість виконувати це безпосередньо через ./script.sh.


2
Ну, це не має ніякої різниці, вважаючи, що /bin/bashце перше bashу вашому $PATH.
cjm

Ти правий. А шебанг #!/bin/bashпрацює лише за наявності/bin/bash
xx4h

Bash (версія 4.2.37) в моїй системі виконує сценарії навіть без встановленого біта виконання. Чому, на вашу думку, потрібен біт виконання?
SkyDan

Так, біт виконання потрібен лише шляхом виклику через ./script.sh.
xx4h

4

Створіть файл Delete_Self.sh так:

 #!/bin/rm

 echo I am still here!

Запустіть цей сценарій, як sh Delete_Self.shви побачите "Я все ще тут!" відлунав назад.

Зробіть його виконуваним і запустіть так, як ./Delete_Self.shви побачите, що нічого не повторюється назад, поки сам файл Delete_Self.shне зник.

Отже, різниця полягає в тому, що:

  • bash script.shігнорує #! рядок, тому що bash вказаний як програма для запуску script.sh.
  • ./script.shпрочитає #! рядок для визначення програми для запуску script.sh.

+1 за хороший приклад
ThisaruG

1

На додаток до інших відповідей, корисне знання різниці між запуском сценарію через ./script.sh(i) та джерелом ./script.sh(ii) - версія (i) створює нову оболонку, в якій можна запустити команду, тоді як (ii) запускає її в поточна оболонка - що може бути обов'язковим, якщо виконуваний файл змінює змінні середовища, які потрібно зберегти після завершення виконання файлу. Наприклад, для активації середовища python conda необхідно використовувати наступне:

source activate my_env

NB Ще одна альтернатива тому, sourceщо ви можете зіткнутися, - це .вбудований, тобто

. activate my_env
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.