检测脚本是否在 Lua 中导入或执行
Detect Whether Script Was Imported or Executed in Lua
在python中,有一个常用的构造形式if __name__ == "__main__":
来检测文件是导入还是直接执行。通常,在这个条件下采取的唯一行动是执行一些“明智的,顶级”功能。这允许将同一个文件用作基本脚本和库模块(以及交互式用户可以导入和使用的东西)。
我想知道 lua 中是否有干净可靠的方法来执行此操作。我以为我可以使用 _REQUIREDNAME 全局变量,但事实证明这在 Lua 5.1 中已更改。目前,lua require
传递参数(在可变参数 ...
中),因此原则上可以检查这些参数。但是,这要么不可靠,要么不干净,或者可能两者兼而有之,因为显然在执行脚本时可以传递参数。因此,要安全地执行此操作,您必须检查参数。
FWIW,require
将模块名称作为参数 1(您调用 require
的字符串)传递,并将最终找到的文件路径作为参数 2 传递。所以显然有一个可以进行一些检查来尝试检测这一点,如果它不如 if __name__ == "__main__":
好,并且用户总是可以通过将两个适当构造的参数传递给脚本来绕过它。不完全是安全威胁,但我希望有更好的解决方案。
我还尝试了另一种方法,我发现它很丑但很有前途。这是为了使用debug.traceack()
。如果直接执行脚本,traceback 非常可预测,实际上它只有 3 行。我认为这可能就是它,虽然,就像我说的,肯定是一个丑陋的 hack。
有没有更频繁的lua用户有什么建议?实际上,如果我正在编写模块 X,我想在脚本模式下 return X.main_func()
或在导入模式下 return X
。
编辑:
我取出了一个实际上不正确的项目(并使我的回溯解决方案可行)。此外,Egor Skriptunoff 在评论中提供的 link 确实提供了调试库中的另一个技巧,它比使用回溯更清晰。除此之外,似乎每个人 运行 都和我有同样的问题,lua 团队对提供官方支持手段不感兴趣。
根据 Egor 提供的链接,目前最干净、最安全的方法似乎如下所示:
我重复一遍以方便参考:
if pcall(debug.getlocal, 4, 1) then
print("in package")
else
print("in main script")
end
这里有一整条讨论帖:
http://lua.2524044.n2.nabble.com/Modules-with-standalone-main-program-td7681497.html
就像我说的,这似乎是一个流行的功能,暂时将不受支持,但 debug.getlocal 方法似乎是 lua 开发人员已经确定的常见方法现在。
A require()
在 package.loaded
返回。
因此,只需检查 package.loaded 您想要的内容即可。
此外,作为在该方法方面获得更多经验的良好开端,我建议为 require() 内容编写 package.preload 函数,而无需操纵路径。
一个简单的例子来展示这个...
# /usr/local/bin/lua -i
Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio
> package.preload.mymod=function() return {dump=function(...)
>> local args={...}
>> local test,dump=pcall(assert,args[1])
>> if test then
>> for key,value in pairs(dump) do
>> io.write(string.format("%s=%s\n",key,value)):flush()
>> end
>> return true
>> else
>> return test,dump
>> end
>> end} end
> mymod=require('mymod')
> mymod.dump(package.loaded)
string=table: 0x56693590
mymod=table: 0x566aa890
utf8=table: 0x56694d80
package=table: 0x56691ed0
math=table: 0x56693cb0
table=table: 0x566920d0
_G=table: 0x56690730
debug=table: 0x566950e0
coroutine=table: 0x56692310
os=table: 0x56692e60
io=table: 0x566921b0
true
在python中,有一个常用的构造形式if __name__ == "__main__":
来检测文件是导入还是直接执行。通常,在这个条件下采取的唯一行动是执行一些“明智的,顶级”功能。这允许将同一个文件用作基本脚本和库模块(以及交互式用户可以导入和使用的东西)。
我想知道 lua 中是否有干净可靠的方法来执行此操作。我以为我可以使用 _REQUIREDNAME 全局变量,但事实证明这在 Lua 5.1 中已更改。目前,lua require
传递参数(在可变参数 ...
中),因此原则上可以检查这些参数。但是,这要么不可靠,要么不干净,或者可能两者兼而有之,因为显然在执行脚本时可以传递参数。因此,要安全地执行此操作,您必须检查参数。
FWIW,require
将模块名称作为参数 1(您调用 require
的字符串)传递,并将最终找到的文件路径作为参数 2 传递。所以显然有一个可以进行一些检查来尝试检测这一点,如果它不如 if __name__ == "__main__":
好,并且用户总是可以通过将两个适当构造的参数传递给脚本来绕过它。不完全是安全威胁,但我希望有更好的解决方案。
我还尝试了另一种方法,我发现它很丑但很有前途。这是为了使用debug.traceack()
。如果直接执行脚本,traceback 非常可预测,实际上它只有 3 行。我认为这可能就是它,虽然,就像我说的,肯定是一个丑陋的 hack。
有没有更频繁的lua用户有什么建议?实际上,如果我正在编写模块 X,我想在脚本模式下 return X.main_func()
或在导入模式下 return X
。
编辑: 我取出了一个实际上不正确的项目(并使我的回溯解决方案可行)。此外,Egor Skriptunoff 在评论中提供的 link 确实提供了调试库中的另一个技巧,它比使用回溯更清晰。除此之外,似乎每个人 运行 都和我有同样的问题,lua 团队对提供官方支持手段不感兴趣。
根据 Egor 提供的链接,目前最干净、最安全的方法似乎如下所示:
我重复一遍以方便参考:
if pcall(debug.getlocal, 4, 1) then
print("in package")
else
print("in main script")
end
这里有一整条讨论帖:
http://lua.2524044.n2.nabble.com/Modules-with-standalone-main-program-td7681497.html
就像我说的,这似乎是一个流行的功能,暂时将不受支持,但 debug.getlocal 方法似乎是 lua 开发人员已经确定的常见方法现在。
A require()
在 package.loaded
返回。
因此,只需检查 package.loaded 您想要的内容即可。
此外,作为在该方法方面获得更多经验的良好开端,我建议为 require() 内容编写 package.preload 函数,而无需操纵路径。
一个简单的例子来展示这个...
# /usr/local/bin/lua -i
Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio
> package.preload.mymod=function() return {dump=function(...)
>> local args={...}
>> local test,dump=pcall(assert,args[1])
>> if test then
>> for key,value in pairs(dump) do
>> io.write(string.format("%s=%s\n",key,value)):flush()
>> end
>> return true
>> else
>> return test,dump
>> end
>> end} end
> mymod=require('mymod')
> mymod.dump(package.loaded)
string=table: 0x56693590
mymod=table: 0x566aa890
utf8=table: 0x56694d80
package=table: 0x56691ed0
math=table: 0x56693cb0
table=table: 0x566920d0
_G=table: 0x56690730
debug=table: 0x566950e0
coroutine=table: 0x56692310
os=table: 0x56692e60
io=table: 0x566921b0
true