web-dev-qa-db-ja.com

関数から呼び出されたときにBashの「ソース」コマンドの動作が異なるのはなぜですか?

次のsourceable bar Bashスクリプトがあるとします...

echo :$#:"$@":

...および次の実行可能ファイルfoo Bashスクリプト:

echo -n source bar:
source bar
echo -n source bar foo:
source bar foo

function _import {
  source "$@"
}

echo -n _import bar:
_import bar
echo -n _import bar foo:
_import bar foo

foo Bashスクリプト、つまり./fooを実行すると、次の出力が表示されます。

source bar::0::
source bar foo::1:foo:
_import bar::1:bar:
_import bar foo::1:foo:

ここに私の質問があります:

  1. 直接ではなく、_import関数からBashのsourceコマンドを呼び出すと、なぜ違いが生じるのですか?
  2. Bashのsourceコマンドの動作を正規化するにはどうすればよいですか?

Fedoraバージョン20でBashバージョン4.2.47(1)-releaseを使用しています。

6
Tim Friske

Gnoucの答えは私の最初の質問を説明します:「直接ではなく、_import関数からBashのソースコマンドを呼び出すとき、なぜ違いがあるのですか?」

2つ目の質問について:「Bashのソースコマンドの動作を正規化するにはどうすればよいですか?」

私は次の答えを見つけたと思います:

_import関数:

function _import {
  local -r file="$1"
  shift
  source "$file" "$@"
}

foo Bashスクリプトを実行すると、次の出力が得られます。つまり、./foo

source bar::0::
source bar foo::1:foo:
_import bar::0::
_import bar foo::1:foo:

私の質問とこの答えの背後にある根拠:「インポートされた」Bashスクリプトは、インポート中に何も指定されていない場合でも、Bashの位置パラメータと特殊パラメータを介して独自の引数セットを評価できるはずです。インポートするBashスクリプトに渡される可能性のある引数は、インポートされるBashスクリプトに暗黙的に渡されてはなりません。

3
Tim Friske

現在の環境でsource実行ファイルが原因の問題。また、bashでは、位置パラメータが指定されていない場合、変更されません。 bashから Bourne Shell Builtins のマニュアルページ:

。 (期間)

。ファイル名[引数]

現在のシェルコンテキストのファイル名引数からコマンドを読み取り、実行します。ファイル名にスラッシュが含まれていない場合、PATH変数を使用してファイル名が検索されます。 BashがPOSIXモードでない場合、ファイル名が$ PATHで見つからない場合、現在のディレクトリが検索されます。 引数が指定されている場合、それらはfilenameが実行されるときの位置パラメータになります。それ以外の場合、位置パラメータは変更されません。戻りステータスは、最後に実行されたコマンドの終了ステータス、またはコマンドが実行されていない場合はゼロです。ファイル名が見つからないか、読み取ることができない場合、戻りステータスはゼロ以外です。この組み込みはソースと同等です。

POSIXは dot を定義します(sourcedotbashと同義です):

シェルは、現在の環境でファイルからコマンドを実行します。

また、ドットのKornShellバージョンは、位置パラメーターに設定されたオプションの引数を取ることができることも説明しました。

KornShellバージョンのドットは、定位置パラメーターに設定されるオプションの引数を取ります。これは、ドットスクリプトが関数と同じように動作できるようにする有効な拡張機能です。

そのため、source bar関数内で_importを呼び出す場合、位置パラメータは指定しないため、変更されません。これらは_import関数スコープと同じで、$@にはbarが含まれ、$#1です(_import barを実行するため)。

source bar関数スコープの外で_importを呼び出すと、グローバルスコープ(またはfooスクリプト)と同じになります。この場合、./fooを実行するので、引数なしでfooを実行します。$@はnullで、$#はゼロです。

4
cuonglm