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

bash linux script

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:

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


タイトルとURLをコピーしました