AのようなBashスクリプトを実行するのと、BのようなBashスクリプトをソースするのは何が違うのでしょうか?
A
> ./myscript
B
> source myscript
336 Scottie T 2009-12-11
スクリプトのソースは、現在のシェルプロセスでコマンドを実行します
スクリプトを実行すると、新しいシェルプロセスでコマンドが実行されます
現在実行中のシェルの環境を変更したい場合はsourceを使用します
まだ迷っている方は、ぜひ読んでみてください
Terminology
実行する構文とソースへの構文に関する共通の混乱を明確にするために
./myscript
これは、ファイルが実行可能でカレントディレクトリにあることを条件にmyscript
を実行します。先頭のドットとスラッシュ (./
) はカレントディレクトリを表します。これは、カレントディレクトリが$PATH
にない(はずの)場合が多いので、必要です
myscript
これは、ファイルが実行可能でmyscript
が$PATH
のどこかのディレクトリにある場合に実行されます
source myscript
これは myscript
をソースにします。ファイルは実行可能である必要はありませんが、有効なシェルスクリプトでなければなりません。ファイルはカレントディレクトリか $PATH
のディレクトリに置くことができます
. myscript
これはmyscript
もソースになります。この「スペル」は POSIX で定義されている公式のものです。Bash はドットのエイリアスとして source
を定義しています
Demonstration
myscript.sh
を以下の内容で考えてみましょう
#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD
スクリプトを実行する前に、まず現在の環境を確認します
$ env | grep FOO
$ echo $PWD
/home/lesmana
変数FOO
が定義されていないので、ホームディレクトリにいます
今度はファイルを実行します
$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
もう一度、環境を確認してみましょう
$ env | grep FOO
$ echo $PWD
/home/lesmana
変数FOO
が設定されておらず、作業ディレクトリが変更されていません
スクリプトの出力を見ると、変数が設定されていて、ディレクトリが変更されていることがはっきりとわかります。その後のチェックでは、変数が設定されておらず、ディレクトリも変更されていないことがわかります。何が起こったのでしょうか?変更は新しいシェルで行われました。現在のシェルはスクリプトを実行するために新しいシェルをスポーンしました。スクリプトは新しいシェルで実行されており、環境へのすべての変更は新しいシェルで有効になります。スクリプトの実行後、新しいシェルは破棄されます。新しいシェルでの環境への変更はすべて新しいシェルで破棄されます。現在のシェルでは、出力テキストのみが印刷されます
今度はファイルをソースにします
$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
もう一度、環境を確認してみましょう
$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir
変数fooが設定され、作業ディレクトリが変更されました
スクリプトをソースにしても新しいシェルは作成されません。すべてのコマンドは現在のシェルで実行され、環境への変更は現在のシェルで有効になります
この単純な例では、実行の出力はスクリプトのソースと同じであることに注意してください。これは必ずしもそうとは限りません
Another Demonstration
以下のスクリプトpid.sh
を考えてみましょう
#!/bin/sh
echo $$
(特別な変数 $$
は現在実行中のシェルプロセスの PID に展開されます)
まず、現在のシェルのPIDを表示します
$ echo $$
25009
スクリプトをソースにします
$ source pid.sh
25009
スクリプトを実行し、PIDをメモします
$ ./pid.sh
25011
Source again:
$ source pid.sh
25009
Execute again:
$ ./pid.sh
25013
スクリプトのソースは同じプロセスで実行され、スクリプトを実行すると毎回新しいプロセスが作成されることがわかります。この新しいプロセスは、スクリプトの実行のために作成された新しいシェルです。スクリプトをソースとして実行しても新しいシェルは作成されないので、PIDは同じままです
Summary
スクリプトのソースと実行の両方とも、スクリプト内のコマンドを一行ずつ手で入力したように実行します
違いがあるのです
- スクリプトを実行すると、新しいシェルを開き、新しいシェルでコマンドを入力し、出力を現在のシェルにコピーしてから新しいシェルを閉じます。環境の変更は新しいシェルでのみ有効で、新しいシェルを閉じると失われます
- スクリプトのソースを作成する際には、現在のシェルでコマンドを入力します。環境の変更は、現在のシェルに反映されます
現在実行中のシェルの環境を変更したい場合はsourceを使用します
See also:
- https://stackoverflow.com/questions/6331075/why-do-you-need-dot-slash-before-script-name-to-run-it-in-bash
- https://askubuntu.com/questions/182012/is-there-a-difference-between-and-source-in-bash-after-all
414 lesmana 2010-08-16
スクリプトを実行すると、スクリプトは別の子プロセスで実行されます。これは、スクリプトで定義されている環境変数などは、親(現在の)シェルでは更新できないことを意味します
スクリプトをソースするということは、現在のシェル自体が解析して実行するということです。あたかもスクリプトの内容を入力したかのようになります。このため、ソースとなるスクリプトは実行可能である必要はありません。しかし、もちろん実行しているのであれば実行可能でなければなりません
現在のシェルに位置引数がある場合、それらは変更されません
ということで、a.sh
を含むファイルがあるとします
echo a $*
と、私はそうしています
$ set `date`
$ source ./a.sh
みたいなものを手に入れる
a Fri Dec 11 07:34:17 PST 2009
Whereas:
$ set `date`
$ ./a.sh
gives me:
a
それが役に立つことを願っています
24 Alok 2009-12-11
sourcing は基本的には、コマンドプロンプトでスクリプトの各行を一度に一つずつ入力するのと同じです
実行は新しいプロセスを開始し、スクリプトの各行を実行し、それが返すものによって現在の環境を変更するだけです
9 John Weldon 2009-12-11
上記に加えて、./myscript
でスクリプトを実行するとファイル myscript の実行権限が必要になりますが、sourcing は実行権限を必要としません。そのため、source myscript
の前に chmod +x myscript
は必要ありません
7 abs 2012-02-23
ソースコードを使用すると、スクリプト内で定義されている余分な変数をすべて取得できます。 したがって、設定や関数の定義がある場合は、実行ではなくソースコードを使うべきです。実行は親環境から独立しています
5 Arkaitz Jimenez 2009-12-11
私の記憶が正しければ、スクリプトを実行すると、スクリプトファイルを引数として #!
行の実行ファイルが実行されます (通常は新しいシェルを起動し、#!/bin/sh
のようにスクリプトを効果的に新しいシェルにソースすることになります)
3 None 2009-12-11
source
コマンドは現在のシェル環境で提供されたスクリプトを実行し(実行許可は必須ではありません)、./
コマンドは新しいシェルで提供された実行可能なスクリプトを実行します
また、例としてこの回答を確認してください。https://superuser.com/a/894748/432100
3 Harsh Vakharia 2015-03-27