为什么可以使用`BASH_SOURCE`来获取执行脚本的当前目录?

为什么可以使用`BASH_SOURCE`来获取执行脚本的当前目录?

我使用source( .)$HOME/.bash_profile从本地文件执行命令$HOME/.dotfiles/.bash_profile

[[ -r "$HOME/.dotfiles/.bash_profile" ]] && . "$HOME/.dotfiles/.bash_profile" 

现在, in$HOME/.dotfiles/.bash_profile$0值为"-bash",这意味着它不能用于dirname检索正在执行的脚本的当前目录。

我读过BASH_SOURCE应该用执行脚本的名称填充(并且它有效!)。

为什么当执行脚本被定义为与 shell 函数对应的源文件名数组时,是否BASH_SOURCE保存执行脚本的名称?man bash

此外,由于BASH_SOURCE被定义为一个数组,因此按如下方式使用它来检索执行脚本的当前目录是不安全的,因为它可以保存多个值dirname $BASH_SOURCE

man bash:

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]}.

答案1

但是BASH_SOURCE,当执行脚本在 man bash 中定义为与 shell 函数对应的源文件名数组时,为什么要保存执行脚本的名称呢?

为什么?可能是因为拥有可用的主脚本的文件名也很有用。

我们看一下手册中的描述:

BASH_SOURCE
FUNCNAME一个数组变量,其成员是源文件名,其中定义了数组变量 中相应的 shell 函数名称。 shell函数${FUNCNAME[$i]}在文件中定义${BASH_SOURCE[$i]}并从${BASH_SOURCE[$i+1]}

FUNCNAME
一个数组变量,包含当前执行调用堆栈中的所有 shell 函数的名称。索引为 0 的元素是任何当前正在执行的 shell 函数的名称。最底部的元素(索引最高的元素)是“main”。

foo在从主脚本调用的函数中,${FUNCNAME[0]}包含foo${BASH_SOURCE[0]}包含定义的文件的名称foo${FUNCNAME[1]}包含main${BASH_SOURCE[1]}包含主脚本文件的名称。

对于FUNCNAME,明确指出在函数之外它是空的。因为BASH_SOURCE它不同。始终在末尾添加主脚本文件的名称的扩展BASH_SOURCE有点合乎逻辑:函数调用和返回只需要在前面添加/删除元素。

它没有这么说,但BASH_SOURCE也跟踪源脚本(. foo.sh或类似的脚本)。FUNCNAME只要没有调用任何函数,它们也不会显示,但当source前面有实际函数时,它们就会显示。

此外,由于BASH_SOURCE被定义为一个数组,因此按如下方式使用它来检索执行脚本的当前目录是不安全的,因为它可以保存多个值dirname $BASH_SOURCE

我不确定这是一个问题还是一个陈述。但请记住,引用没有索引的数组与使用索引相同0$BASH_SOURCE也是如此${BASH_SOURCE[0]},并且包含定义当前函数的文件的名称。 (不是主脚本的那个,因为你需要类似的东西${BASH_SOURCE[ ${#BASH_SOURCE[@]} - 1 ]}。)

请注意,文件名可能仍然类似于./foo.shfoo.sh,因此dirname可能无法告诉任何有用的信息。

相关内容