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

Существует несколько способов выполнения сценария, которые я знаю:

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

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

8 Solutions collect form web for “Различные способы выполнения сценария оболочки”

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

 /bin/sh /path/to/script 

Точка и источник эквивалентны. (EDIT: нет, это не так: поскольку KeithB указывает на комментарий к другому ответу, «.» Работает только в связанных с bash оболочках, где «источник» работает как в оболочках bash, так и в csh.) Он выполняет сценарий в -place (как если бы вы скопировали и вставили скрипт прямо там). Это означает, что все функции и нелокальные переменные в скрипте остаются. Это также означает, что если скрипт создает cd в каталог, вы все равно будете там, когда это будет сделано.

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

/ path / to / script и / bin / sh немного отличаются. Как правило, сценарий имеет «shebang» в начале, который выглядит так:

 #! /bin/bash 

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

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

 #! /bin/perl 

а также

 #! /bin/ruby 

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

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

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

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

 eval sh script eval script eval . script 

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

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

 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 ... ... 

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

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

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

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

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

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

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

 cat foo.sh | dash dash < foo.sh 

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

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

 sh script bash script 

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

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

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

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

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

 source file 

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

 . file 

не требуется

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

Запускает скрипт в текущей оболочке, когда каталог не находится в пути.

  • Как автоматически сканировать документы на Linux с терминала?
  • Есть ли простой способ сделать эквивалент `sed ...` заменяя одну и ту же строку несколькими значениями?
  • как сделать большую командную строку, разбитую на две строки, выполняться как одна строка внутри скрипта
  • regexp в ksh для расширений tgz, tar.tgz
  • Как назначить одну переменную на слово строки
  • Запустить сценарий и не потерять доступ к подсказке / терминалу
  • Как удалить место во всех подкаталогах в сценарии оболочки?
  • bc удаляет десятичную точку
  • Выполнение скриптов оболочки bash
  • Loop в скрипте на удаленном сервере не работает
  • Проверить IP-адрес в диапазоне белого списка
  • Linux и Unix - лучшая ОС в мире.