В чем разница между запуском «bash script.sh» и «./script.sh»?

43

Если script.sh это просто что-то вроде

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

Есть ли предпочтительный способ запуска скрипта? Я думаю, что вы должны сначала выполнить chmod, чтобы он стал исполняемым?

user72136
источник

Ответы:

57

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


Причина разницы в требованиях к разрешениям заключается в том, как загружается программа, которая интерпретирует ваш скрипт:

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

Оболочка разветвляется и использует системный вызов (например execve), чтобы заставить операционную систему выполнить файл в разветвленном процессе. Операционная система проверит права доступа к файлу (следовательно, необходимо установить бит выполнения) и направит запрос загрузчику программы , который просматривает файл и определяет, как его выполнить. В Linux скомпилированные исполняемые файлы начинаются с магического числа ELF , а сценарии начинаются с #!( hashbang ). Заголовок hashbang означает, что файл является сценарием и должен интерпретироваться программой, указанной после hashbang. Это позволяет самому сценарию сообщать системе, как интерпретировать сценарий.

С вашим скриптом загрузчик программы будет выполнен /bin/bashи передан ./script.sh в качестве аргумента командной строки.

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

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


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

Скидан
источник
3
Если исполняемый бит не установлен, вы также можете запустить скрипт, выполнив «./script.sh»
Dog eat cat world
1
@ Собака Вы правы. Точка - это ярлык для встроенной команды «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команды и вы их набираете, он может выйти из системы. Менее страшная проблема будет, если скрипт выполнит cd, поскольку это также повлияет на родительскую (интерактивную) оболочку.
Скотт
18

bash script.shвызывает скрипт напрямую с помощью bash.
./script.shиспользует Шебанг, #!/bin/bashчтобы определить, как выполнить.

Если вы действительно хотите знать, какой двоичный файл выполняется, если вы сделаете a, bash script.shвы можете узнать с помощью which bash.

Так что в вашем примере это не имеет значения. Да, вы должны chmod +x script.shиметь возможность выполнить его напрямую через ./script.sh.

xx4h
источник
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) и source ./script.sh(ii) - версия (i) создает новую оболочку для запуска команды, тогда как (ii) запускает ее в текущая оболочка - которая может быть обязательной, если исполняемый файл изменяет переменные среды, которые необходимо сохранить после выхода из исполняемого файла. Например, чтобы активировать среду Python Conda, необходимо использовать следующее:

source activate my_env

NB. Другой альтернативой, с sourceкоторой вы можете столкнуться, является .встроенная функция, т.е.

. activate my_env
einonm
источник