注意:对于posix兼容的解决方案,请参阅此答案。
${BASH_SOURCE[0]}(或者更简单地说,$BASH_SOURCE[1]
)包含所有调用场景中包含脚本的路径(可能是相对的),特别是当脚本是源脚本时,这对于$0来说不是真的。
此外,正如Charles Duffy指出的那样,调用者可以将$0设置为任意值。
另一方面,如果没有命名文件,$BASH_SOURCE可以为空;例如:
echo 'echo "[$BASH_SOURCE]"' | bash . sh
下面的例子说明了这一点:
脚本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[0]},您可以编写$arr;换句话说:如果你引用变量,就好像它是一个标量,你得到的元素的下标为0。
使用这个特性掩盖了$arr是一个数组的事实,这就是为什么流行的shell-code linter shellcheck.net会发出以下警告(在撰写本文时):
SC2128:展开一个没有索引的数组只给出第一个元素。
附注:虽然这个警告是有用的,但它可以更精确,因为您不一定会得到第一个元素:它返回的是索引为0的元素,因此如果第一个元素具有更高的索引(这在Bash中是可能的),您将得到空字符串;试一试[1]=“嗨”;回声“美元”。
(相比之下,zsh,始终是叛逆者,将所有元素作为一个单独的字符串返回,以第一个字符分隔。存储在$IFS中,默认为空格)。
由于它的模糊性,您可以选择避开这个特性,但它的工作方式是可以预见的,而且从实际意义上讲,您几乎不需要访问数组变量${BASH_SOURCE[@]}的除0以外的索引。
可选阅读,第2部分:BASH_SOURCE数组变量在什么条件下实际上包含多个元素?:
BASH_SOURCE只有在涉及函数调用时才有多个条目,在这种情况下,它的元素与包含当前调用堆栈上所有函数名的FUNCNAME数组并行。
也就是说,在函数内部,${FUNCNAME[0]}包含执行函数的名称,${BASH_SOURCE[0]}包含定义该函数的脚本文件的路径,${FUNCNAME[1]}包含调用当前执行函数的函数名(如果适用的话),等等。
如果一个给定的函数是直接从脚本文件的顶层作用域调用的,该脚本文件在调用堆栈的$i级定义了函数,${FUNCNAME[$i+1]}包含:
Main(一个伪函数名),如果直接调用脚本文件(例如,./script)
Source(伪函数名),如果脚本文件是源文件(例如Source ./script或. ./script)。