如何在 Bash 源代码中查找变量名称



我正在编写一个允许本地函数命名空间的实验性 Bash 模块系统,我的第一个想法是编写一个 Bash 函数解析器,它将逐行读取函数代码,并在每个函数/变量名称前面加上<module-name>.(即模块module中的函数func将变为module.func- 可以再次导入到另一个模块中,如module_2.module.func等等; 函数内的变量将被名称破坏 - 变量 模块module中的函数func内的var将变为__module_func_var(。

但是,为了做到这一点,我需要一种方法来检测哪些名称是变量,并用传输的导入名称替换它们在函数中的所有出现。像variable=[...]这样的琐碎情况很容易解析,但还有无数其他情况不是那么微不足道——while read variable; do [...] donevariable2="asdf${variable//_/+}"呢?

在我看来,为了做到这一点,我需要深入研究 Bash 的解析机制或阅读一本关于编程语言的书 - 但是为了实现我上面解释的内容,我从哪里开始呢?

我需要一种方法来检测哪些名称是变量

我很抱歉这么说,但总的来说这是不可能的。

仅支持可能发生变量的静态情况是可能的,但非常棘手。只考虑变量赋值:除了x=之外,还有declare x=printf -v xread xmapfile xreadarray x等等。即使是像shellcheck这样的成熟工具,在正确解析所有这些情况时仍然存在问题(例如,请参阅此问题(。

但是,即使您掌握了正确解析所有静态情况,仍然可以通过动态变量,例如:

x=$(someCommand)
declare "$x=something"

在此示例中,如果不执行someCommand,您将无法知道新变量的名称。其他同样(甚至(更糟糕的事情是bash的间接算子${!x},算术上下文中的隐式间接(例如x=y; echo $((x))(,eval.

tl;dr:获取脚本中所有变量的唯一方法是解释/执行脚本。

但这里又出现了另一个问题:如果存在非确定性(declare "$(tr -cd a-z /dev/urandom | head -c1)=..."(,执行脚本也不是一种选择。请注意,用户输入也是不确定的(read x; declare "var$x=..."(。您必须编写静态分析器。但由于停止问题,这也不是一个选择。从停止问题中,我们可以推断出(通常(不可能判断给定的 bash 脚本是否具有有限数量的变量。


要实现您的模块系统,您可以使用另一种方法。例如,如果有人想为您的框架实现一个模块,那么他们必须以简单的可解析格式指定该模块中的函数/变量。

最新更新