2009-12-11 15:24:17 +0000 2009-12-11 15:24:17 +0000
302
302

Bash スクリプトの実行とソースの違いは何ですか?

AのようなBashスクリプトを実行するのと、BのようなBashスクリプトをソースするのは何が違うのでしょうか?

A
> ./myscript

B
> source myscript

回答 (6)

369
369
369
2010-08-16 21:58:48 +0000

ソース スクリプトは current シェルプロセスでコマンドを実行します。

Executing スクリプトは new シェルプロセスでコマンドを実行します。

現在実行中のシェルの環境を変更させたい場合はsourceを使用してください。

まだ混乱している場合は、先を読んでください。

./myscript
myscript

これは、ファイルが実行可能でカレントディレクトリ内にある場合に限り、 実行 myscript となります。先頭のドットとスラッシュ (./) はカレントディレクトリを示します。これは、カレントディレクトリは通常$PATHには存在しない(すべきではない)ため、必要です。

source myscript

これは、ファイルが実行可能であり、myscriptのどこかのディレクトリにある場合に 実行 $PATH を実行します。

. myscript

これはソース myscriptを生成する。ファイルは実行可能である必要はありませんが、有効なシェルスクリプトでなければなりません。ファイルはカレントディレクトリまたは$PATHのディレクトリにあります。

#!/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

これも ソース myscript となります。この「スペル」は POSIX で定義されている公式のものです。Bash はドットの別名として source を定義しています。

デモ

myscript.sh を以下の内容で考えてみます。

$ env | grep FOO
$ echo $PWD
/home/lesmana

スクリプトを実行する前に、まず現在の環境を確認します。

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

変数FOOは定義されておらず、ホームディレクトリにあります。

$ env | grep FOO
$ echo $PWD
/home/lesmana

FOO 変数pid.shが定義されておらず、ホームディレクトリにあります。

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

環境を再度チェックしてみます:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

変数 $$ が設定されておらず、作業ディレクトリも変更されていません。

スクリプトの出力を見ると、明らかに変数が設定されており、ディレクトリが変更されていることがわかります。その後のチェックでは、変数が設定されておらず、ディレクトリも変更されていないことがわかります。何が起こったのでしょうか?変更はnewシェルで行われました。currentシェルはスクリプトを実行するためにnew_シェルをスポーンしました。スクリプトは新しいシェルで実行されており、環境へのすべての変更は新しいシェルで有効になります。スクリプトの実行後、新しいシェルは破棄されます。新しいシェルでの環境へのすべての変更は、新しいシェルで破棄されます。現在のシェルでは出力テキストのみが印刷されます。

ここでソースファイルを作成します。

#!/bin/sh
echo $$
$ echo $$
25009

環境を再度確認します:

$ source pid.sh
25009

変数fooが設定され、作業ディレクトリが変更されています。

スクリプトをソースしても新しいシェルは作成されません。すべてのコマンドは現在のシェルで実行され、環境への変更は現在のシェルで有効になります。

この単純な例では、実行時の出力はスクリプトのソースコードと同じであることに注意してください。これは必ずしもそうとは限りません。

別のデモンストレーション

以下のスクリプト 0x6& を考えてみましょう。

$ ./pid.sh
25011

(特殊変数0x6&は現在実行中のシェルプロセスのPIDに展開)

最初に現在のシェルのPIDを表示する:

$ source pid.sh
25009

スクリプトのソース。

$ ./pid.sh
25013

スクリプトを実行して PID を記録する:

0x1&

ソースを再度実行する:

0x1&

スクリプトを再度実行する:

0x1&

スクリプトをソースとして実行すると同じプロセスで実行される一方で、スクリプトを実行すると毎回新しいプロセスが作成されることがわかります。この新しいプロセスは、スクリプトの実行のために作成された new シェルです。スクリプトのソースを実行しても新しいシェルは作成されないので、PIDは同じままです。

まとめ

スクリプトのソースを実行しても、スクリプトを実行しても、まるで手でコマンドを一行一行入力したかのように、スクリプト内のコマンドが一行一行実行されます。

違いは以下の通りです。

  • スクリプトを execute する際には new シェルを開き、新しいシェルにコマンドを入力し、出力を現在のシェルにコピーしてから新しいシェルを閉じます。環境の変更は新しいシェルでのみ有効となり、新しいシェルを閉じると失われます。
  • スクリプトを source した場合、current シェルでコマンドを入力しています。環境への変更はすべて現在のシェルで有効になり、そのままになります。

現在実行中のシェルの環境を変更したい場合は source を使用してください。


参照。

23
23
23
2009-12-11 15:35:56 +0000

スクリプトを実行すると、スクリプトは別の子プロセスで実行されます。これは、スクリプトで定義された環境変数などは、親(現在の)シェルでは更新できないことを意味します。

スクリプトをソースするということは、現在のシェル自体がスクリプトを解析して実行することを意味します。あたかもスクリプトの内容を入力したかのようになります。このため、ソースとなるスクリプトは実行可能である必要はありません。しかし、もちろん実行しているのであれば実行可能でなければなりません。

現在のシェルに位置引数がある場合、それは変更されません。

echo a $*

を含むファイル a.sh があって、それを実行したとします。

$ set `date`
$ source ./a.sh

を実行すると、以下のようになります。

a Fri Dec 11 07:34:17 PST 2009

のようになります。

$ set `date`
$ ./a.sh

とすると次のようになります:

a

となります。

9
9
9
2009-12-11 15:27:08 +0000

sourcing は基本的に、コマンドプロンプトでスクリプトの各行を一度に一つずつ入力するのと同じです…

実行は新しいプロセスを開始し、スクリプトの各行を実行します。

6
6
6
2012-02-23 07:27:43 +0000

上記に加えて、./myscriptとしてスクリプトを実行するにはファイル myscript の実行権限が必要ですが、sourcing では実行権限は必要ありません。そのため、chmod +x myscript の前には source myscript は必要ありません。

5
5
5
2009-12-11 15:25:38 +0000

ソースを実行すると、スクリプト内で定義されている余分な変数をすべて取得します。
なので、設定や関数の定義がある場合は、実行ではなくソースを取るべきです。実行は親環境から独立しています。

2
2
2
2015-03-27 14:04:20 +0000

source コマンドは現在のシェル環境で提供されたスクリプト(実行許可は必須ではありません )を実行し、./新しいシェルで提供された実行可能なスクリプトを実行します。

また、この回答を例として確認してみてください。 https://superuser.com/a/894748/432100