如何在"$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]}
Run Code Online (Sandbox Code Playgroud)
mkl*_*nt0 137
${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]}]"
Run Code Online (Sandbox Code Playgroud)
$ bash ./foo
[./foo] vs. [./foo]
$ ./foo
[./foo] vs. [./foo]
$ . ./foo
[bash] vs. [./foo]
Run Code Online (Sandbox Code Playgroud)
$0
是POSIX shell规范的一部分,而BASH_SOURCE
顾名思义,它是特定于Bash的.
[1] 可选阅读:${BASH_SOURCE[0]}
vs$BASH_SOURCE
.
击允许引用元件0
的的阵列使用可变标量表示法:代替书写${arr[0]}
,可以编写$arr
; 换句话说:如果你引用变量就好像它是一个标量,你就得到了索引元素0
.
使用此功能掩盖了$arr
数组的事实,这就是流行的shell-code linter shellcheck.net发出以下警告的原因(截至撰写本文时):
SC2128:扩展没有索引的数组只给出了第一个元素.
旁注:虽然这个警告很有用,但它可能更精确,因为你不一定会得到第一个元素:它特别0
是返回索引的元素,所以如果第一个元素有一个更高的索引 -在Bash中是可能的 - 你会得到空字符串; 试试'a[1]='hi'; echo "$a"'
.
(相比之下,zsh
叛徒,无论其指数如何,确实会返回第一个元素).
您可以选择避开这一功能,因为它默默无闻,但它的工作原理可以预见和务实地讲,你会很少,如果有的话,需要访问索引其他比0
数组变量${BASH_SOURCE[@]}
.
it-*_*ien 28
TL;DR我建议使用${BASH_SOURCE:-$0}
作为最通用的变体。
以前的答案很好,但他们没有提到${BASH_SOURCE[0]}
直接使用的一个警告:如果您调用脚本作为sh
的参数,并且您sh
没有别名bash
(在我的例子中,在 Ubuntu 16.04.5 LTS 上,它链接到dash
),它可能因BASH_SOURCE
变量为空/未定义而失败。这是一个例子:
t.sh:
#!/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}]"
Run Code Online (Sandbox Code Playgroud)
(成功)运行:
$ ./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]
Run Code Online (Sandbox Code Playgroud)
最后:
$ sh t.sh
$0: [t.sh]
$BASH_SOURCE: []
$BASH_SOURCE or $0: [t.sh]
t.sh: 6: t.sh: Bad substitution
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,只有第三个变体:${BASH_SOURCE:-$0}
- 在所有调用场景下都有效并给出一致的结果。请注意,我们利用bash 的功能来引用等于第一个数组元素的无下标数组变量。
Huw*_*ers 10
这些脚本可能有助于说明。外部脚本调用中间脚本,中间脚本调用内部脚本:
$ cat outer.sh
#!/usr/bin/env bash
./middle.sh
Run Code Online (Sandbox Code Playgroud)
$ cat middle.sh
#!/usr/bin/env bash
./inner.sh
Run Code Online (Sandbox Code Playgroud)
$ 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]}'"
Run Code Online (Sandbox Code Playgroud)
$ ./outer.sh
$0 = './inner.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = ''
$BASH_SOURCE[2] = ''
Run Code Online (Sandbox Code Playgroud)
但是,如果我们将脚本调用更改为source
语句:
$ cat outer.sh
#!/usr/bin/env bash
source ./middle.sh
Run Code Online (Sandbox Code Playgroud)
$ cat middle.sh
#!/usr/bin/env bash
source ./inner.sh
Run Code Online (Sandbox Code Playgroud)
$ 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]}'"
Run Code Online (Sandbox Code Playgroud)
$ ./outer.sh
$0 = './outer.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = './middle.sh'
$BASH_SOURCE[2] = './outer.sh'
Run Code Online (Sandbox Code Playgroud)
use*_*610 10
为了可移植性,${BASH_SOURCE[0]}
在定义时使用,$0
否则使用。那给
${BASH_SOURCE[0]:-$0}
Run Code Online (Sandbox Code Playgroud)
值得注意的是,在 zsh 中,即使脚本是source
d ,$0 也确实包含正确的文件路径。