次のフォルダ構造を持つ小さなプログラムがあります。
- main.sh
- lib/
- clean.sh
- get.sh
- index.sh
- test.sh
各ファイルにはiが含まれていますmain.sh
。
main.sh
:
source lib/*
get_products
clean_products
make_index
test_index
上記の例では、最初の2つの関数は機能しますが、最後の2つの関数は機能しません。
しかし、次のように置き換えるとsource lib/*
:
source lib/get.sh
source lib/clean.sh
source lib/index.sh
source lib/test.sh
すべてが期待どおりに動作します。
source lib/*
これが期待どおりに機能しない理由を知っている人はいますか?
答え1
Bashのsource
組み込みコマンドは単一のファイル名のみを使用します。
source filename [arguments]
最初の引数以外のすべての引数は位置引数になりますfilename
。
簡単な例:
$ cat myfile
echo "param1: $1"
$ source myfile foo
param1: foo
すべての出力help source
source: source filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.
.
(これは特にPOSIXなので、移植性の良い組み込みの「ポイントソース」にも適用されます。)
見ている見かけに矛盾する動作については、完了後にmain.shを実行してみることができますset -x
。どの文がいつ実行されたかを確認すると、手がかりを得ることができます。
答え2
バッシュ文書source
単一に適用されることを示します。ファイル名:
。 (一定期間)
。ファイル名[論争]
次のコマンドを読んで実行します。ファイル名現在のシェルコンテキストのパラメータです。もしファイル名...
そしてソースコード...源泉...これをサポートします。
result = source_file (filename, (list && list->next));
source_file
定義はどこにありますか?evalfile.c
呼ぶ_evalfile
:
rval = _evalfile (filename, flags);
そして_evalfile
ファイルだけを開きます。
fd = open (filename, O_RDONLY);
答え3
補完的なレイヤbに対する有用な答え、拡張したいタイプのファイルが存在するかどうかわからない場合は、貪欲なグローバル拡張を使用しないことをお勧めします。
次の操作を実行すると(拡張子なし)、ファイルが実行される可能性のある有害なコマンド(実行権限があると仮定)を含む一時ファイルの.sh
ように見えることがあります。rm -rf *
source lib/*
したがって、*.sh
ファイルを個別に繰り返すことができますが、常にグローバル拡張に適切なバインディングセットを使用してください。
for globFile in lib/*.sh; do
[ -f "$globFile" ] || continue
source "$globFile"
done
これは、現在のフォルダに一致するグローバルパターンがない場合は[ -f "$globFile" ] || continue
ループから返されます。これはシェルの拡張シェルオプションと同じです。nullglob
bash