【发布时间】:2011-09-16 20:56:30
【问题描述】:
我想知道是否有办法获取当前正在执行的 lua 脚本文件的路径?
这不是当前的工作目录,可能完全不同。我知道luafilesystem会让我得到当前的工作目录,但它似乎无法告诉当前正在执行的脚本文件。
谢谢
编辑: 我不是从标准命令行解释器运行的,而是通过luabind 从 C++ 二进制文件执行脚本。
【问题讨论】:
标签: filesystems lua
我想知道是否有办法获取当前正在执行的 lua 脚本文件的路径?
这不是当前的工作目录,可能完全不同。我知道luafilesystem会让我得到当前的工作目录,但它似乎无法告诉当前正在执行的脚本文件。
谢谢
编辑: 我不是从标准命令行解释器运行的,而是通过luabind 从 C++ 二进制文件执行脚本。
【问题讨论】:
标签: filesystems lua
这是一种更优雅的方式:
function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*/)")
end
print(script_path())
【讨论】:
lua myscript(其中lua假设这意味着./myscript),该函数返回nil。我建议使用return str:match("(.*/)") or "."
str:match("(.*/)") 替换为 str:match("(.*[/\\])")
如果 Lua 脚本正在由标准命令行解释器运行,请尝试 arg[0]。
【讨论】:
dofile 使用它获得的任何路径,因此相对路径是相对于进程的当前工作目录的。如果你想跟踪给dofile的文件,你可以重新定义它。
... 仅返回与arg[1] 等价的值。
...? arg[0] 确实适用于 Lua 5.3。
正如 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 获得
【讨论】:
我发现的最短形式如下:
debug.getinfo(1).source:match("@?(.*/)")
索引 1、2- 其他 - 取决于您要查询的调用堆栈中的哪个函数。 1 是最后一次调用的函数(您所在的位置)。如果您在全局环境中运行,那么可能 2 更合适(我自己没有测试过)
【讨论】:
arg[0]:match("@?(.*/)") 适合我从控制台运行。
获得所需内容的唯一可靠方法是将dofile 替换为您自己版本的此函数。即使debug.getinfo 方法也不起作用,因为它只会返回传递给dofile 的字符串。如果那是相对路径,它不知道它是如何转换为绝对路径的。
覆盖代码如下所示:
local function CreateDoFile()
local orgDoFile = dofile;
return function(filename)
if(filename) then --can be called with nil.
local pathToFile = extractFilePath(filename);
if(isRelativePath(pathToFile)) then
pathToFile = currentDir() .. "/" .. pathToFile;
end
--Store the path in a global, overwriting the previous value.
path = pathToFile;
end
return orgDoFile(filename); --proper tail call.
end
end
dofile = CreateDoFile(); //Override the old.
函数extractFilePath、isRelativePath和currentDir不是Lua函数;你必须自己写。 extractFilePath 函数从文件名中提取路径字符串。 isRelativePath 接受路径并返回给定路径是否为相对路径名。 currentDir 只是返回当前目录。此外,您需要在 Windows 机器上使用“\”而不是“/”。
此函数将路径存储在名为path 的全局变量中。您可以将其更改为您喜欢的任何内容。
【讨论】:
/ 用于 Windows 路径。
我编写了一个函数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%") 更改为您提供的任何命令操作系统中的工作目录,例如io.popen("pwd") 用于 Linux,第 18 行 中的 pwd2:sub(2,3) == ":/" 表示操作系统中的根目录,例如pwd2:sub(1,1) == "/" 用于 Linux。
注意2:如果你在调用函数时没有通过debug.getinfo(1).source将source变量提供给函数,那么它将返回文件所在目录的路径这个函数。因此,如果您想获取通过dofile 或loadfile 调用的文件的目录,则必须为其提供源,如下所示:getScriptDir(debug.getinfo(1).source)。
【讨论】:
查看 Lua 调试库,它是标准 Lua 发行版的一部分。您可以使用 debug.getinfo 查找当前文件,或调用堆栈上 N 帧的文件:
http://www.lua.org/manual/5.1/manual.html#5.9
请注意,这可能相当慢,因此如果您担心此类事情,则不希望在快速路径上执行此操作。
【讨论】:
如果你想要实际路径:
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
【讨论】:
arg[0]:match('.*\\')
如果它返回 nil,请尝试将 .\*\\\ 更改为 .*/ 并将 arg[0] 更改为 debug.getinfo(1).short_src。
但我发现这是获取当前目录的最佳和最短的方法。
您当然可以使用.. 运算符附加您要查找的文件。它看起来像这样:
arg[0]:match('.*\\')..'file.lua'
【讨论】: