Ответ 1
Если Lua script выполняется стандартным интерпретатором командной строки, попробуйте arg[0]
.
Мне интересно, есть ли способ получить путь к текущему исполняемому файлу lua script?
Это не текущий рабочий каталог, который может быть совершенно другим. Я знаю luafilesystem позволит мне получить текущий рабочий каталог, но он, похоже, не может сказать текущее выполнение script файл.
Спасибо
EDIT: Я не запускаюсь из стандартного интерпретатора командной строки, я выполняю скрипты из двоичного кода С++ через luabind.
Если Lua script выполняется стандартным интерпретатором командной строки, попробуйте arg[0]
.
Это более элегантный способ:
function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*/)")
end
print(script_path())
Как говорит 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$
Это доступно из API C lua_getinfo
Единственный надежный способ получить то, что вы хотите, - заменить 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
. Вы можете изменить это, как хотите.
Самая короткая форма, которую я нашел, выглядит следующим образом:
debug.getinfo(1).source:match("@?(.*/)")
Индекс 1, 2- другой - зависит от того, какую функцию в стеке вызовов вы хотите запросить. 1 - последняя функция (где вы находитесь). Если вы работаете в глобальном контексте, то, вероятно, 2 более подходит (не проверял сам)
Посмотрите библиотеку отладки Lua, которая является частью стандартного дистрибутива Lua. Вы можете использовать debug.getinfo для поиска текущего файла или файла N кадров в стеке вызовов:
http://www.lua.org/manual/5.1/manual.html#5.9
Обратите внимание, что это, вероятно, довольно медленно, поэтому вы не хотите делать это на быстром пути, если вас беспокоят такие вещи.
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))
else использовать это для полного пути к файлу:
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, вам нужно изменить io.popen("echo %cd%")
в строке 15 на любую команду, которая дает вам подарок рабочий каталог в вашей ОС, например io.popen("pwd")
для Linux и pwd2:sub(2,3) == ":/"
в строке 18, что представляет собой корневой каталог в вашей ОС, например. pwd2:sub(1,1) == "/"
для Linux.
Примечание2:, если вы не предоставляете переменную source
функции через debug.getinfo(1).source
при ее вызове, она вернет путь к каталогу файла, содержащего эту функцию. Поэтому, если вы хотите получить каталог файла, который вы вызвали через dofile
или loadfile
, вам нужно будет предоставить ему источник, например: getScriptDir(debug.getinfo(1).source)
.