在$ 0和BASH_SOURCE之间选择

时间:2016-01-26 03:10:43

标签: bash

如何在"$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]}

4 个答案:

答案 0 :(得分:113)

${BASH_SOURCE[0]}(或者更简单地说,$BASH_SOURCE [1] )包含所有调用方案中包含脚本的(可能相对)路径,特别是当脚本是 sourced 时,$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 shell规范的一部分,而BASH_SOURCE,顾名思义,是特定于Bash的。

[1] 可选阅读:${BASH_SOURCE[0]}$BASH_SOURCE

Bash允许您使用标量表示法引用数组变量的元素0:而不是编写${arr[0]},您可以编写{{ 1}};换句话说:如果您引用变量就好像它是标量,那么您将获得索引$arr处的元素。

使用此功能掩盖了0是一个数组的事实,这就是流行的shell-code linter shellcheck.net发出以下警告的原因(截至撰写本文时):

  

SC2128:扩展没有索引的数组只会给出第一个元素。

旁注:虽然此警告有用,但它可能更精确,因为您不一定会获得第一个元素:它特别是索引$arr处的元素返回,所以如果第一个元素有一个更高的索引 - 这可能在Bash中 - 你将获得空字符串;试试0 (相比之下,'a[1]='hi'; echo "$a"',叛徒,确实确实返回第一个元素,无论其索引如何。)

你可以选择避开这个功能,因为它的含糊不清,但它可以预测,并且从实用角度来说,你很少需要访问索引其他而不是zsh数组变量0

答案 1 :(得分:4)

为便于携带,请在定义时使用${BASH_SOURCE[0]},否则使用$0。这样

${BASH_SOURCE[0]:-$0}

值得注意的是,在zsh中,即使脚本为source d,$ 0仍包含正确的文件路径。

答案 2 :(得分:2)

这些脚本可能有助于说明。外部脚本调用中间脚本,中间脚本调用内部脚本:

$ 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'

答案 3 :(得分:0)

TL;DR 我建议使用 1.52.94 作为最通用的变体。

以前的答案很好,但他们没有提到直接使用 ${BASH_SOURCE:-$0} 的警告:如果您将脚本作为 ${BASH_SOURCE[0]} 的参数调用,并且您的 sh 没有别名为 {{ 1}}(就我而言,在 Ubuntu 16.04.5 LTS 上,它链接到 sh),它可能会因 bash 变量为空/未定义而失败。举个例子:

t.sh:

dash

(成功)运行:

BASH_SOURCE

最后:

#!/usr/bin/env bash

echo "\$0:                    [$0]"
echo "\$BASH_SOURCE:          [$BASH_SOURCE]"
echo "\$BASH_SOURCE or \$0:    [${BASH_SOURCE:-$0}]"
echo "\$BASH_SOURCE[0] or \$0: [${BASH_SOURCE[0]:-$0}]"

简历

如您所见,只有第三个变体:$ ./t.sh $0: [./t.sh] $BASH_SOURCE: [./t.sh] $BASH_SOURCE or $0: [./t.sh] $BASH_SOURCE[0] or $0: [./t.sh] $ source ./t.sh $0: [/bin/bash] $BASH_SOURCE: [./t.sh] $BASH_SOURCE or $0: [./t.sh] $BASH_SOURCE[0] or $0: [./t.sh] $ bash t.sh $0: [t.sh] $BASH_SOURCE: [t.sh] $BASH_SOURCE or $0: [t.sh] $BASH_SOURCE[0] or $0: [t.sh] - 在所有调用场景下都有效并给出一致的结果。请注意,我们利用 bash's feature 来引用等于第一个数组元素的无下标数组变量。