获取 Lua 文件的包含路径
我想知道是否有一种方法可以获取当前正在执行的 lua 脚本文件的路径?
这个问题特别不是当前工作目录,可能完全不同。我知道 luafilesystem 可以让我获取当前工作目录,但它似乎不能告诉我当前正在执行的脚本文件。
谢谢
编辑: 我不是从标准命令行解释器执行,我是通过 luabind 从 C++ 二进制文件执行脚本。
原文链接 https://stackoverflow.com/questions/6380820
如lhf所说:
~ e$ echo "print(arg[0])" > test.lua
~ e$ lua test.lua
test.lua
~ e$ cd /
/ e$ lua ~/test.lua
/Users/e/test.lua
/ e$
以下是使用debug.getinfo机制相同的信息
~ e$ echo "function foo () print(debug.getinfo(1).source) end; foo()" > test.lua
~ e$ lua test.lua
@test.lua
~ e$ cd /
/ e$ lua ~/test.lua
@/Users/e/test.lua
/ e$
这可以从C API [lua_getinfo]中获得(http://www.lua.org/manual/5.1/manual.html#lua_getinfo)
请看 Lua 调试库,它是标准 Lua 分发的一部分。您可以使用 debug.getinfo 找到当前文件,或者在调用堆栈上向上 N 个帧的文件:
http://www.lua.org/manual/5.1/manual.html#5.9
请注意,这可能相当慢,因此如果您担心这些事情,这不是您想在快速路径上做的事情。
唯一可靠的方法是将 dofile
替换为这个函数的自定义版本才能得到想要的结果。即使使用 debug.getinfo
方法也不行,因为它只会返回传递给 dofile
的字符串。如果它是相对路径,那么它不知道它是如何被转换为绝对路径的。
重载代码应该如下:
local function CreateDoFile()
local orgDoFile = dofile;
return function(filename)
if(filename) then --可以使用 nil 调用。
local pathToFile = extractFilePath(filename);
if(isRelativePath(pathToFile)) then
pathToFile = currentDir() .. "/" .. pathToFile;
end
--将路径存储在全局变量中,覆盖以前的值。
path = pathToFile;
end
return orgDoFile(filename); --正确的尾调用。
end
end
dofile = CreateDoFile(); //覆盖旧的。
函数 extractFilePath
, isRelativePath
, 和 currentDir
都不是 Lua 函数;你需要自己编写它们。 extractFilePath
函数从文件名中提取一个路径字符串。isRelativePath
接受一个路径并返回给定路径是否为相对路径名。 currentDir
简单地返回当前目录。此外,在 Windows 机器上需要使用 "\" 而不是 "/"。
此函数将路径存储在名为 path
的全局变量中。你可以将其更改为任何你喜欢的名字。
这是一种更优雅的方法:
function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*/)")
end
print(script_path())
我找到的最短形式看起来像这样:
debug.getinfo(1).source:match("@?(.*/)")
索引1,2- 其他- 取决于您要查询哪个调用堆栈中的函数。 1是最后调用的函数(您所在的函数)。如果您在全局上下文中运行,则可能更适合使用2(我还没有自己测试过)。
arg[0]:match('.*\\')
如果返回值为 nil,则尝试使用 .*/
替换 .\*\\\
,并将 arg[0]
替换为 debug.getinfo(1).short_src
。
但我发现这是获取当前目录的最佳且最短的方法。
当然,您可以使用 ..
运算符将要查找的文件附加到当前目录。它将如下所示:
arg[0]:match('.*\\')..'file.lua'
如果你想要实际路径:
path.dirname(path.abspath(debug.getinfo(1).short_src))
否则,使用此选项获取完整文件路径:
path.abspath(debug.getinfo(1).short_src)
如果希望获得包括文件名在内的真实路径,只需要使用以下代码
pathWithFilename=io.popen("cd"):read'*all'
print(pathWithFilename)
测试于Windows环境。
解释:
io.popen
- 发送命令到命令行并返回输出。
"cd"
- 在cmd
中用户输入该命令获取当前路径。
:read'*all'
- 由于io.popen返回一个类似于文件的对象,所以您可以使用相同类型的命令来读取它。 这会读取整个输出。
如果需要UNC路径:
function GetUNCPath(path,filename)
local DriveLetter=io.popen("cd "..path.." && echo %CD:~0,2%"):read'*l'
local NetPath=io.popen("net use "..DriveLetter):read'*all'
local NetRoot=NetPath:match("[^\n]*[\n]%a*%s*([%a*%p*]*)")
local PathTMP=io.popen("cd "..path.." && cd"):read'*l'
PathTMP=PathTMP:sub(3,-1)
UNCPath=NetRoot..PathTMP.."\\"..filename
return UNCPath
end
我写了一个函数getScriptDir
,它使用了类似其他人建议的调试信息,但这个函数会一直运行(至少在Windows上)。但问题是它使用了另一个我创建的函数string.cut
,这个函数可以按给定的模式分隔字符串,并将其放入表中,因此代码有点长。
function string.cut(s,pattern)
if pattern == nil then pattern = " " end
local cutstring = {}
local i1 = 0
repeat
i2 = nil
local i2 = string.find(s,pattern,i1+1)
if i2 == nil then i2 = string.len(s)+1 end
table.insert(cutstring,string.sub(s,i1+1,i2-1))
i1 = i2
until i2 == string.len(s)+1
return cutstring
end
function getScriptDir(source)
if source == nil then
source = debug.getinfo(1).source
end
local pwd1 = (io.popen("echo %cd%"):read("*l")):gsub("\\","/")
local pwd2 = source:sub(2):gsub("\\","/")
local pwd = ""
if pwd2:sub(2,3) == ":/" then
pwd = pwd2:sub(1,pwd2:find("[^/]*%.lua")-1)
else
local path1 = string.cut(pwd1:sub(4),"/")
local path2 = string.cut(pwd2,"/")
for i = 1,#path2-1 do
if path2[i] == ".." then
table.remove(path1)
else
table.insert(path1,path2[i])
end
end
pwd = pwd1:sub(1,3)
for i = 1,#path1 do
pwd = pwd..path1[i].."/"
end
end
return pwd
end
注意:如果您想在除Windows以外的其他操作系统中使用此函数,则需要将第15行的io.popen("echo %cd%")
更改为给您的操作系统提供当前工作目录的命令,例如Linux的io.popen("pwd")
,并将第18行的pwd2:sub(2,3) == ":/"
更改为您的操作系统中表示根目录的任何内容,例如Linux的pwd2:sub(1,1) == "/"
。
注意2:如果您在调用函数时没有通过debug.getinfo(1).source
提供source
变量给函数,那么它将返回包含该函数的文件的目录路径。因此,如果您想获取通过dofile
或loadfile
调用的文件的目录路径,则必须将源代码作为参数传递给它,例如:getScriptDir(debug.getinfo(1).source)
。
这个版本的 anthonygore 的回答 是跨平台的(能处理 Windows 反斜杠路径),并且在没有路径时运行脚本(返回相对路径)。
local function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*[/\\])") or "./"
end
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
如果Lua脚本是由标准命令行解释器运行的,则尝试使用
arg[0]
。