Получить содержащий путь файла lua - PullRequest
17 голосов
/ 17 июня 2011

Мне интересно, есть ли способ получить путь к исполняемому в настоящее время файлу сценария lua?

Это конкретно не текущий рабочий каталог, который может быть совершенно другим.Я знаю, luafilesystem позволит мне получить текущий рабочий каталог, но, похоже, он не сможет определить текущий файл исполняемого скрипта.

Спасибо

РЕДАКТИРОВАТЬ:Я не запускаю стандартный интерпретатор командной строки, я выполняю сценарии из двоичного файла C ++ с помощью luabind .

Ответы [ 10 ]

15 голосов
/ 08 мая 2014

Это более элегантный способ:

function script_path()
   local str = debug.getinfo(2, "S").source:sub(2)
   return str:match("(.*/)")
end

print(script_path())
6 голосов
/ 17 июня 2011

Если скрипт Lua запускается стандартным интерпретатором командной строки, попробуйте arg[0].

3 голосов
/ 17 июня 2011

Единственный надежный способ получить то, что вы хотите, - это заменить 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.Вы можете изменить это на то, что вам нравится.

3 голосов
/ 17 июня 2011

Как говорит ЛХФ:

~ 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

2 голосов
/ 29 января 2016

Кратчайшая форма, которую я нашел, выглядит следующим образом:

debug.getinfo(1).source:match("@?(.*/)")

Индекс 1, 2 - другое - зависит от того, какую функцию в стеке вызовов вы хотите запросить.1 - последняя вызванная функция (где вы находитесь).Если вы работаете в глобальном контексте, то, вероятно, 2 более подходит (не проверял сам)

0 голосов
/ 05 декабря 2017

Я написал функцию 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).

0 голосов
/ 20 октября 2017

Если вам нужен реальный путь, включая имя файла, просто используйте следующее

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
0 голосов
/ 24 сентября 2017

, если вы хотите фактический путь:

path.dirname(path.abspath(debug.getinfo(1).short_src))

иначе используйте это для полного пути к файлу:

path.abspath(debug.getinfo(1).short_src)
0 голосов
/ 28 августа 2016
arg[0]:match('.*\\')

Если возвращается ноль, попробуйте изменить .\*\\\ на .*/ и arg[0] на debug.getinfo(1).short_src.

Но я считаю, что это лучший и самый короткий способ получить текущий каталог.

Конечно, вы можете добавить искомый файл с помощью оператора ... Это будет выглядеть примерно так:

arg[0]:match('.*\\')..'file.lua'
0 голосов
/ 17 июня 2011

Посмотрите библиотеку отладки Lua, которая является частью стандартного дистрибутива Lua.Вы можете использовать debug.getinfo, чтобы найти текущий файл, или файл размером N кадров в стеке вызовов:

http://www.lua.org/manual/5.1/manual.html#5.9

Обратите внимание, что это, вероятно, довольно медленно, поэтому это не такчто-то, что вы хотите сделать на быстром пути, если вы беспокоитесь о таких вещах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...