web-dev-qa-db-ja.com

Bashスクリプトを実行することとそれを調達することの違いは何ですか。

AのようなBashスクリプトを実行することとBのようなBashスクリプトを調達することの違いは何ですか?

A
> ./myscript

B
> source myscript
265
Scottie T

短い答え

Sourcingスクリプトは、currentShellプロセス内のコマンドを実行します。

スクリプトを実行すると、newShellプロセスでコマンドが実行されます。

あなたがまだ混乱しているならば、読んでください。

用語

実行する構文とソースへの構文に関する一般的な混乱を明確にするには、次のようにします。

./myscript

これはexecutemyscriptになります。ただし、ファイルが実行可能であり、現在のディレクトリにあると仮定します。先頭のドットとスラッシュ(./)は現在のディレクトリを表します。現在のディレクトリは通常$PATHには含まれていないので(そして通常はそうすべきではありません)、これは必要です。

myscript

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

source myscript

これはsourcemyscriptになります。ファイルは実行可能ファイルである必要はありませんが、有効なシェルスクリプトである必要があります。ファイルは現在のディレクトリまたは$PATH内のディレクトリにあります。

. myscript

これはsourcemyscriptにもなります。この「綴り」は POSIX で定義されている公式のものです。 Bashはsourceをドットの別名として定義しました。

デモンストレーション

以下の内容の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が定義されておらず、ホームディレクトリにいます。

executeファイル:

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

環境をもう一度確認してください。

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

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

スクリプトの出力は、変数が設定され、ディレクトリが変更されたことを明確に示しています。その後のチェックは、変数が設定されておらず、ディレクトリも変更されていないことを示しています。何が起こった?変更はnewShellで行われました。currentShellは、newShellを生成してスクリプトを実行しました。スクリプトは新しいシェルで実行されており、環境に対するすべての変更は新しいシェルで有効になります。スクリプトが実行された後、新しいシェルは破壊されます。新しいシェルの環境に対するすべての変更は、新しいシェルによって破棄されます。出力テキストだけが現在のシェルに表示されます。

sourceファイル:

$ 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が設定され、作業ディレクトリが変更されました。

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

この簡単な例では、実行の出力はスクリプトの取得と同じです。これは必ずしもそうとは限らない。

もう一つのデモンストレーション

以下のスクリプトpid.shを考えてください。

#!/bin/sh
echo $$

(特殊変数$$は、現在実行中のシェルプロセスのPIDに展開されます)

最初に現在のシェルのPIDを表示します。

$ echo $$
25009

スクリプトを入手します。

$ source pid.sh
25009

スクリプトを実行し、PIDを書き留めます。

$ ./pid.sh
25011

もう一度ソース:

$ source pid.sh
25009

再度実行してください。

$ ./pid.sh
25013

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

概要

スクリプトの実行と実行の両方で、あたかも手動で1行ずつコマンドを入力した場合と同様に、スクリプト内のコマンドが1行ずつ実行されます。

違いは次のとおりです。

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

スクリプトを実行しているシェルの環境を変更する場合は、sourceを使用してください。それ以外の場合はexecuteを使用してください。


また見なさい:

329
lesmana

スクリプトを実行すると、別の子プロセスでスクリプトが実行されます。つまり、スクリプトを処理するためにShellの別のインスタンスが呼び出されます。つまり、スクリプトで定義されている環境変数などは、親(現在の)シェルでは更新できません

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

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

だから私はa.shを含むファイルがあるなら:

echo a $*

そして私はします:

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

私は何かのようになる:

a Fri Dec 11 07:34:17 PST 2009

一方、

$ set `date`
$ ./a.sh

私にくれます:

a

それが役立つことを願っています。

21
Alok

ソーシングは基本的には、コマンドプロンプトでスクリプトの各行を1行ずつ入力するのと同じです。

実行は新しいプロセスを開始してからスクリプトの各行を実行し、現在の環境をそれが返すものだけで変更します。

9
John Weldon

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

6
abs

調達すると、スクリプトで定義されたすべての追加の変数が得られます。
それでもしあなたが設定や関数定義を持っているならば、あなたは実行するべきではなく調達すべきです。実行は両親の環境から独立しています。

5
Arkaitz Jimenez

思い出してみると、スクリプトを実行すると、スクリプトファイルを引数として、#!行の実行可能ファイルが実行されます(通常は、新しいシェルを起動し、#!/bin/shの場合と同じようにスクリプトを新しいシェルに送ります)。
一方、スクリプトを読み込むと現在のシェル環境の各行が実行されます。これは、現在のシェルを変更するのに役立ちます(たとえば、シェル関数を定義して環境変数をエクスポートする方法を提供します)。

3
fd

sourceコマンドは、提供されたスクリプトを実行します(実行許可は必須ではありませんcurrentShell環境、./newShellで提供されたexecutableスクリプトを実行します。

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

2
Harsh Vakharia