在不污染全局环境的情况下加载文件。

如何在不污染全局环境的情况下加载一个包含 Lua 表和变量的文件?因为仅仅使用 loadfile 并运行它会将所有内容加载到全局空间中,并可能覆盖其他我不想要的变量。

原文链接 https://stackoverflow.com/questions/9540732

点赞
stackoverflow用户68204
stackoverflow用户68204

在 Lua 5.1 中,可以通过以下方式实现没有过多错误处理的运行脚本:

-- 加载并运行提供环境中的脚本
-- 返回修改后的环境表
function run(scriptfile)
    local env = setmetatable({}, {__index=_G})
    assert(pcall(setfenv(assert(loadfile(scriptfile)), env)))
    setmetatable(env, nil)
    return env
end

第一行创建了一个空的环境表,可以访问所有现有的全局变量,但是不能直接更改它们,因为它们仅通过 __index 元方法的代理可见。脚本创建的任何全局变量将存储在 env 中,并被返回。对于只设置一堆配置参数的简单脚本以及可能需要根据运行时条件调用简单安全函数来设置它们的情况,这种方法会很好地工作。

请注意,使全局变量对脚本可见是一种便利。尽管全局变量无法以明显的方式从脚本中修改,但 _G 是一个全局变量,其中包含对全局环境的引用(包含 _G._G_G._G._G 等),并且 _G 可以从脚本中进行修改,这可能会导致进一步的问题。

因此,与其将 _G 用作索引,更好的方法是构建一个仅包含已知安全和脚本作者需要的函数的表。

完整的解决方案是在沙箱中运行脚本,并可能进一步受到保护,以防止意外(或故意)拒绝服务或更糟。沙盒在 Lua 用户维基中有更详细的介绍。这个主题比一开始看起来更加深入,但只要您相信您的用户是非恶意的,实际解决方案就是直截了当的。

Lua 5.2 通过用 load() 的一个新参数代替 setfenv() 改变了一些东西。详细信息也在维基页面中。

2012-03-02 22:39:58
stackoverflow用户44844
stackoverflow用户44844

以下是_RBerteig_的答案的 dofile() 版本,您可以提供环境并返回结果(如果有的话)(我尝试将其作为注释,但无法将其格式化):

local function DofileIntoEnv(filename, env)
    setmetatable ( env, { __index = _G } )
    local status, result = assert(pcall(setfenv(assert(loadfile(filename)), env)))
    setmetatable(env, nil)
    return result
end

我想要能够将多个文件加载到同一个环境中,并且其中一些文件中有一个'return something'。 感谢RBerteig,您的答案非常有帮助和指导!

2013-05-03 20:06:58
stackoverflow用户3317263
stackoverflow用户3317263

在 Lua > 5.2 中

function run_test_script(scriptfile)
    local env = setmetatable({}, {__index=_G})
    assert(pcall(loadfile(scriptfile,"run_test_script",env)))
    setmetatable(env, nil)
    return env
end

``` 函数 run_test_script 可以运行一个脚本文件,并且将这个脚本文件的环境设置为一个新的空表,在此空表中运行脚本文件。在脚本文件执行完之后,将此空表返回。

传入参数:

scriptfile: 字符串类型,表示需要运行的脚本文件路径。

返回值:

env: 表类型,表示脚本文件运行后的环境。```
2021-11-10 09:15:30