it-swarm-ru.tech

Различные способы выполнения сценария оболочки

Есть несколько способов выполнить скрипт, известные мне:

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

Чем больше это? Каковы различия между ними? Есть ли ситуации, в которых я должен использовать одно, а не другое?

44
phunehehe

Другой способ - вызвать интерпретатор и передать ему путь к скрипту:

/bin/sh /path/to/script

Точка и источник эквивалентны. (РЕДАКТИРОВАТЬ: нет, это не так: как указывает KeithB в комментарии к другому ответу, "." Работает только в оболочках, связанных с bash, где "source" работает как в оболочках, связанных с bash, так и csh.) -place (как будто вы скопировали и вставили скрипт прямо там). Это означает, что все функции и нелокальные переменные в скрипте остаются. Это также означает, что если скрипт вставит компакт-диск в каталог, вы все равно будете там, когда это будет сделано.

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

/ path/to/script и/bin/sh script немного отличаются. Как правило, сценарий имеет "Шебанг" в начале, который выглядит следующим образом:

#! /bin/bash

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

Например, сценарии Perl и Ruby начинаются с (соответственно):

#! /bin/Perl

а также

#! /bin/Ruby

Если вы выполните один из этих сценариев, запустив /bin/sh script, тогда они вообще не будут работать.

Ubuntu на самом деле не использует оболочку bash, но очень похожую, называемую dash. Скрипты, которые требуют bash, могут работать немного неправильно при вызове с помощью /bin/sh script потому что вы только что вызвали bash-скрипт, используя dash-интерпретатор.

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

Еще один незначительный вариант: вы можете использовать любой из этих способов выполнения скрипта с помощью eval, так что вы можете иметь

eval sh script
eval script
eval . script

и так далее. На самом деле это ничего не меняет, но я подумал, что включу это для тщательности.

32
Shawn J. Goff

Большинство людей отлаживают сценарии оболочки, добавляя в сценарий следующее отладочные флаги :

set -x     # Print command traces before executing command.
set -v     # Prints Shell input lines as they are read.
set -xv    # Or do both

Но это означает, что вам нужно открыть файл в редакторе (при условии, что у вас есть права на редактирование файла), добавив строку, такую ​​как set -x, сохраните файл, затем запустите файл. Затем, когда вы закончите, вам нужно выполнить те же шаги и удалить set -x и ​​т. д. и т. д. Это может быть утомительно.

Вместо того, чтобы делать все это, вы можете установить флаги отладки в командной строке:

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...
9
Stefan Lasiewski

Шон Дж. Гофф сделал много хороших замечаний, но не включил всю историю:

Ubuntu на самом деле не использует оболочку bash, но очень похожую, называемую dash. Скрипты, которые требуют bash, могут работать немного неправильно при вызове с помощью /bin/sh script, потому что вы только что вызвали bash-скрипт, используя dash-интерпретатор.

Многие системные скрипты (как в init.d, в/etc и т.д.) Имеют Shebang #!/bin/sh, но /bin/sh фактически является символической ссылкой на другой Shell - в прежние времена /bin/bash, В наше время /bin/dash. Но когда один из них вызывается как /bin/sh, они ведут себя по-разному, то есть придерживаются режима совместимости с POSIX.

Как они это делают? Ну, они проверяют, как они были вызваны.

Может ли сам шеллскрипт проверить, как он вызывался, и делать разные вещи, в зависимости от этого? Да, оно может. То, как вы вызываете его, всегда может привести к разным результатам, но, конечно, это редко делается, чтобы вас раздражать. :)

Практическое правило. Если вы изучаете конкретную оболочку, например bash, и пишете команды из учебника по bash, вставьте #!/bin/bash в заголовке, а не #!/bin/sh, если не указано иное. Иначе ваши команды могут потерпеть неудачу. И если вы сами не написали сценарий, вызовите его напрямую (./foo.sh, bar/foo.sh) вместо того, чтобы угадать Shell (sh foo.sh, sh bar/foo.sh). Шебанг должен вызывать правильную Шелл.

И вот два других вида вызова:

cat foo.sh | dash
dash < foo.sh
7
user unknown

. и ​​source эквивалентны тем, что они не порождают подпроцесс, а выполняют команды в текущей оболочке. Это важно, когда скрипт устанавливает переменные среды или изменяет текущий рабочий каталог.

Используя путь или давая его /bin/sh создает новый процесс, в котором выполняются команды.

5
mouviciel
sh script
bash script

Я размышляю, есть ли еще ...

. и ​​source одинаковы. После выполнения любые изменения окружения в script будут сохранены. Обычно он используется для создания библиотеки Bash, поэтому библиотеку можно использовать повторно во многих различных сценариях.

Также это хороший способ сохранить текущий каталог. Если вы измените каталог в скрипте, он не будет применен в командной консоли, в которой вы выполняете этот скрипт. Но если вы его запустите, после выхода из скрипта текущий каталог будет сохранен.

2
livibetter

, и источник немного отличается в Zsh по крайней мере (это то, что я использую), потому что

source file

Работы, в то время как

. file

не нужно

. ./file
1
bollovan
. ./filename
# ( dot space dot slash filename )

Запускает сценарий в текущей командной консоли, когда каталог не указан в пути.

1
jrh_enginnering

" serland exec " считается другим способом? Пользовательский exec загружает код и заставляет его выполняться без использования системного вызова execve ().

1
Bruce Ediger