注意:如果需要符合POSIX标准的解决方案,请参考this answer。
${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 shell 规范的一部分,而 BASH_SOURCE
如其名称所示,是特定于 Bash 的。
[1] 选读: ${BASH_SOURCE[0]}
vs. $BASH_SOURCE
:
Bash允许您使用标量符号引用数组变量的元素0
: 您可以写$arr
,而不是写${arr[0]}
; 换句话说:如果您像引用标量一样引用变量,则会得到索引为0
的元素。
使用此功能会隐藏$arr
是一个数组的事实,这就是为什么流行的shell代码检查器shellcheck.net在此写作时发出以下警告的原因:
SC2128: 扩展没有索引的数组只会给出第一个元素。
顺便提一下:虽然这个警告很有帮助,但它可能会更加精确,因为您不一定会得到第一个元素:特别是返回的是索引0
处的元素,所以如果第一个元素的索引较高 - 这在Bash中是可能的 - 您将得到空字符串;尝试a[1] ='hi'; echo"$a"
。(相比之下,zsh
则返回所有元素作为单个字符串,用默认情况下的空格分隔第一个字符存储在$IFS
中)。
由于其晦涩难懂,您可以选择放弃此功能,但它可预测地工作,并且实际上,您很少或几乎不需要访问除${BASH_SOURCE[@]}
数组变量的索引0之外的索引。
可选阅读,第2部分:什么情况下BASH_SOURCE
数组变量实际上包含多个元素?:
BASH_SOURCE
只有在涉及函数调用的情况下才有多个条目,在这种情况下,它的元素与包含当前调用堆栈上所有函数名称的FUNCNAME
数组相对应。
也就是说,在函数内部,${FUNCNAME[0]}
包含正在执行的函数的名称,${BASH_SOURCE[0]}
包含定义该函数的脚本文件的路径,${FUNCNAME[1]}
包含当前正在执行的函数从中调用的函数的名称(如果适用),依此类推。
如果给定的函数直接从定义函数的脚本文件的顶级作用域中调用,则在调用堆栈的级别$i
处的函数,${FUNCNAME[$i+1]}
包含:
If the script file was invoked directly (e.g., ./script), use "main" (a pseudo function name); If the script file was sourced (e.g. source ./script or . ./script), use "source" (a pseudo function name).
BASH_SOURCE
是在bash-3.0-alpha版本中添加的。根据您的测试环境,您可能没有它。我发现早期Solaris和OS X都缺少它。另请参见U&L.SE上的[return: can only `return' from a function or sourced script](https://unix.stackexchange.com/q/468579/56041)。 - jww