$ 0とBASH_SOURCEの間で選択


118

一つは間どのように選択しない"$0"と、"${BASH_SOURCE[0]}"

GNUからのこの説明は私にはあまり役に立ちませんでした。

    BASH_SOURCE

 An array variable whose members are the source filenames where the
 corresponding shell function names in the FUNCNAME array variable are
 defined. The shell function ${FUNCNAME[$i]} is defined in the file
 ${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}

BASH_SOURCEbash-3.0-alphaで追加されました。テスト体制によっては、それがない場合があります。初期のSolarisとOS Xの両方で欠落していることがわかりました。また、return: U&L.SEの関数またはソーススクリプトからのみ「return」できることも参照してください。
jww 2018年

回答:


174

注:POSIX準拠のソリューションについては、この回答を参照してください。

${BASH_SOURCE[0]}(または、より簡単に言えば、$BASH_SOURCE[1] )には、すべての呼び出しシナリオで、含まれているスクリプトの(潜在的に相対)パスが含まれます。特に、スクリプトがソース化されている場合も同様です$0。これはには当てはまりません。

さらに、Charles Duffyが指摘するように、呼び出し元$0任意の値に設定できます。
反対に、名前付きファイルが含まれていない場合は空にする$BASH_SOURCE ことできます。例えば:
echo 'echo "[$BASH_SOURCE]"' | bash

次の例はこれを示しています。

スクリプトfoo

#!/bin/bash
echo "[$0] vs. [${BASH_SOURCE[0]}]"

$ bash ./foo
[./foo] vs. [./foo]

$ ./foo
[./foo] vs. [./foo]

$ . ./foo
[bash] vs. [./foo]

$0はPOSIXシェル仕様の一部ですBASH_SOURCEが、は名前が示すようにBash固有です。


[1] オプションの読み取り:${BASH_SOURCE[0]}$BASH_SOURCE

Bashでは0スカラー表記を使用して配列変数の要素を参照できます。を書く代わりに、を書くことができます。つまり、変数をスカラーのように参照すると、インデックスに要素が取得されます。 ${arr[0]}$arr0

この機能を使用する$arrと、配列であるという事実がわかりにくくなります。そのため、人気のあるシェルコードリンターshellcheck.netが次の警告を発行します(この記事の執筆時点で)。

SC2128:インデックスなしで配列を拡張すると、最初の要素しか得られません。

余談ですが、この警告は役に立ちますが、必ずしも最初の要素を取得するとは限らないため、より正確になる可能性があります。具体的には、0返されるのはインデックスの要素なので、最初の要素のインデックスが高い場合、 Bashでは可能です-空の文字列を取得します。試してください'a[1]='hi'; echo "$a"'
(これとは対照的に、zshこれまで反乱は、確かにありませんそのインデックスのにかかわらず、最初の要素を返します)。

実用的に言えば、あなたは、そのあいまいにこの機能を避けることを選択するかもしれないが、それは予想どおりに動作して、あなたはめったに、もしこれまでに、アクセスする必要がインデックスしないだろう、他のよりも0配列変数の${BASH_SOURCE[@]}


$ BASH_SOURCEはより一般的で、より多くの状況で機能しますか?
Alexander Mills

2
@AlexanderMillsはい、Bashを使用している場合$BASH_SOURCEは、より良い選択です。
mklement0

18

これらのスクリプトは説明に役立つ場合があります。外側のスクリプトは、内側のスクリプトを呼び出す中間スクリプトを呼び出します。

$ cat outer.sh
#!/usr/bin/env bash
./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './inner.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = ''
$BASH_SOURCE[2] = ''

ただし、スクリプトの呼び出しをsourceステートメントに変更すると、次のようになります。

$ cat outer.sh
#!/usr/bin/env bash
source ./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
source ./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './outer.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = './middle.sh'
$BASH_SOURCE[2] = './outer.sh'

1

移植性のために${BASH_SOURCE[0]}、それが定義されている場合に使用してください$0。それは与える

${BASH_SOURCE[0]:-$0}

特に、zshなどでは、スクリプトがsourcedであっても、$ 0には正しいファイルパスが含まれています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.