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

<p>есть несколько способов выполнить скрипт, известные мне:</p><pre><code>/path/to/script # using the path (absolute or relative) . script # using the . (dot) source script # using the `source` command </code></pre><p>чем больше это? каковы различия между ними? есть ли ситуации, в которых я должен использовать одно, а не другое?</p>

<p>другой способ - вызвать интерпретатор и передать ему путь к скрипту:</p><pre><code>/bin/sh /path/to/script </code></pre><p>точка и источник эквивалентны. (редактировать: нет, это не так: как указывает keithb в комментарии к другому ответу, "." работает только в оболочках, связанных с bash, где "source" работает как в оболочках, связанных с bash, так и csh.) -place (как будто вы скопировали и вставили скрипт прямо там). это означает, что все функции и нелокальные переменные в скрипте остаются. это также означает, что если скрипт вставит компакт-диск в каталог, вы все равно будете там, когда это будет сделано.</p><p>другие способы запуска скрипта будут запускать его в своей собственной оболочке. переменные в скрипте еще не живы, когда это сделано. если скрипт изменил каталоги, то это не влияет на среду вызова.</p><p>/ path/to/script и/bin/sh script немного отличаются. как правило, сценарий имеет "шебанг" в начале, который выглядит следующим образом:</p><pre><code>#! /bin/bash </code></pre><p>это путь к интерпретатору сценария. если он указывает на интерпретатор, отличный от того, который вы делаете при его выполнении, то он может вести себя по-другому (или вообще не работать).</p><p>например, сценарии perl и ruby начинаются с (соответственно):</p><pre><code>#! /bin/perl </code></pre><p>а также</p><pre><code>#! /bin/ruby </code></pre><p>если вы выполните один из этих сценариев, запустив <code>/bin/sh script</code>, тогда они вообще не будут работать.</p><p>ubuntu на самом деле не использует оболочку bash, но очень похожую, называемую dash. скрипты, которые требуют bash, могут работать немного неправильно при вызове с помощью <code>/bin/sh script</code> потому что вы только что вызвали bash-скрипт, используя dash-интерпретатор.</p><p>еще одно небольшое различие между непосредственным вызовом сценария и передачей пути сценария интерпретатору заключается в том, что сценарий должен быть помечен как исполняемый для непосредственного запуска, а не для запуска путем передачи пути к интерпретатору.</p><p>еще один незначительный вариант: вы можете использовать любой из этих способов выполнения скрипта с помощью eval, так что вы можете иметь</p><pre><code>eval sh script eval script eval . script </code></pre><p>и так далее. на самом деле это ничего не меняет, но я подумал, что включу это для тщательности.</p>

<p>большинство людей отлаживают сценарии оболочки, добавляя в сценарий следующее <a href="http://tldp.org/ldp/bash-beginners-guide/html/sect\_02\_03.html#table\_02\_01">отладочные флаги</a> :</p><pre><code>set -x # print command traces before executing command. set -v # prints shell input lines as they are read. set -xv # or do both </code></pre><p>но это означает, что вам нужно открыть файл в редакторе (при условии, что у вас есть права на редактирование файла), добавив строку, такую как <code>set -x</code>, сохраните файл, затем запустите файл. затем, когда вы закончите, вам нужно выполнить те же шаги и удалить <code>set -x</code> и т. д. и т. д. это может быть утомительно.</p><p>вместо того, чтобы делать все это, вы можете установить флаги отладки в командной строке:</p><pre><code>$ 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 ... ... </code></pre>

<p>шон дж. гофф сделал много хороших замечаний, но не включил всю историю:</p><blockquote> <p>ubuntu на самом деле не использует оболочку bash, но очень похожую, называемую dash. скрипты, которые требуют bash, могут работать немного неправильно при вызове с помощью <code>/bin/sh</code> script, потому что вы только что вызвали bash-скрипт, используя dash-интерпретатор.</p> </blockquote><p>многие системные скрипты (как в init.d, в/etc и т.д.) имеют shebang <code>#!/bin/sh</code>, но <code>/bin/sh</code> фактически является символической ссылкой на другой shell - в прежние времена <code>/bin/bash</code>, в наше время <code>/bin/dash</code>. но когда один из них вызывается как <code>/bin/sh</code>, они ведут себя по-разному, то есть придерживаются режима совместимости с posix.</p><p>как они это делают? ну, они проверяют, как они были вызваны.</p><p>может ли сам шеллскрипт проверить, как он вызывался, и делать разные вещи, в зависимости от этого? да, оно может. то, как вы вызываете его, всегда может привести к разным результатам, но, конечно, это редко делается, чтобы вас раздражать. :)</p><p>практическое правило. если вы изучаете конкретную оболочку, например bash, и пишете команды из учебника по bash, вставьте <code>#!/bin/bash</code> в заголовке, а не <code>#!/bin/sh</code>, если не указано иное. иначе ваши команды могут потерпеть неудачу. и если вы сами не написали сценарий, вызовите его напрямую (<code>./foo.sh</code>, <code>bar/foo.sh</code>) вместо того, чтобы угадать shell (<code>sh foo.sh</code>, <code>sh bar/foo.sh</code>). шебанг должен вызывать правильную шелл.</p><p>и вот два других вида вызова:</p><pre><code>cat foo.sh | dash dash < foo.sh </code></pre>

<p><code>.</code> и <code>source</code> эквивалентны тем, что они не порождают подпроцесс, а выполняют команды в текущей оболочке. это важно, когда скрипт устанавливает переменные среды или изменяет текущий рабочий каталог.</p><p>используя путь или давая его <code>/bin/sh</code> создает новый процесс, в котором выполняются команды.</p>

<pre><code>sh script bash script </code></pre><p>я размышляю, есть ли еще ...</p><p><code>.</code> и <code>source</code> одинаковы. после выполнения любые изменения окружения в <code>script</code> будут сохранены. обычно он используется для создания библиотеки bash, поэтому библиотеку можно использовать повторно во многих различных сценариях.</p><p>также это хороший способ сохранить текущий каталог. если вы измените каталог в скрипте, он не будет применен в командной консоли, в которой вы выполняете этот скрипт. но если вы его запустите, после выхода из скрипта текущий каталог будет сохранен.</p>

<p>, и источник немного отличается в zsh по крайней мере (это то, что я использую), потому что</p><pre><code>source file </code></pre><p>работы, в то время как</p><pre><code>. file </code></pre><p>не нужно</p><pre><code>. ./file </code></pre>

<pre><code>. ./filename # ( dot space dot slash filename ) </code></pre><p>запускает сценарий в текущей командной консоли, когда каталог не указан в пути.</p>

<p>" <a href="http://archive.cert.uni-stuttgart.de/bugtraq/2004/01/msg00002.html">serland exec</a> " считается другим способом? пользовательский exec загружает код и заставляет его выполняться без использования системного вызова execve ().</p>