Вземете съдържащия път на lua файла

Чудя се дали има начин да получа пътя до текущо изпълнявания файл на lua скрипт?

Това конкретно не е текущата работна директория, която може да е напълно различна. Знам, че luafilesystem ще ми позволи да получа текущата работна директория, но изглежда не да можете да кажете текущия изпълняващ се скрипт файл.

Благодаря

РЕДАКТИРАНЕ: Не стартирам от стандартния интерпретатор на командния ред, изпълнявам скриптовете от C++ двоичен файл чрез luabind.


person radman    schedule 17.06.2011    source източник


Отговори (10)


Ако скриптът Lua се изпълнява от стандартния интерпретатор на командния ред, опитайте arg[0].

person lhf    schedule 17.06.2011
comment
Ако направих dofile(subfile) в оригинала, ще работи ли този метод за получаване на пътя на подфайла? - person radman; 17.06.2011
comment
@radman: не. Освен това dofile използва какъвто и път да получи и така относителните пътища са относителни към текущата работна директория на процеса. Ако искате да проследявате файлове, дадени на dofile, можете да го предефинирате. - person lhf; 17.06.2011
comment
и потребителят може също да използва loadfile и след това да стартира заредения файл като извикване на функция, може да се наложи да предефинирате също loadfile - person baye; 10.03.2014
comment
За съжаление, това не работи в Lua 5.3. ... на основния блок връща само еквивалента на arg[1] нататък. - person Hisham H M; 01.06.2016
comment
@HishamHM, кой каза нещо за ...? arg[0] работи с Lua 5.3. - person lhf; 01.06.2016
comment
@lhf, съжалявам, обърках нещата с arg във varargs, които изчезват, след като бяха отхвърлени в Lua 5.1. Наистина, разчитането на arg работи при стартиране на скрипт директно от интерпретатор, но не и при зареждане на същия скрипт с loadfile. - person Hisham H M; 09.06.2016

Това е по-елегантен начин:

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

print(script_path())
person anthonygore    schedule 08.05.2014
comment
Ако скриптът се изпълнява без път, като например lua myscript (в който lua приема, че това означава ./myscript), тази функция връща nil. Предлагам да използвате return str:match("(.*/)") or "." - person Hisham H M; 01.06.2016
comment
За да работи това на Windows, заменете str:match("(.*/)") с str:match("(.*[/\\])") - person tversteeg; 12.12.2017

Както казва 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

person Doug Currie    schedule 17.06.2011

Най-кратката форма, която намерих, изглежда така:

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

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

person TarmoPikaro    schedule 28.01.2016
comment
arg[0]:match("@?(.*/)") е работа за мен при изпълнение от конзолата. - person Tim; 11.01.2017

Единственият надежден начин да получите това, което искате, е да замените 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. Можете да промените това на каквото искате.

person Nicol Bolas    schedule 17.06.2011
comment
fyi, можете перфектно да използвате / и за пътища на Windows. - person jpjacobs; 17.06.2011
comment
също loadfile трябва да бъде заменен - person baye; 23.01.2013

Написах функция 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).

person Amine Kchouk    schedule 05.12.2017

Разгледайте библиотеката за отстраняване на грешки в Lua, която е част от стандартната дистрибуция на Lua. Можете да използвате debug.getinfo, за да намерите текущия файл или файла до N кадъра в стека за повиквания:

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

Имайте предвид, че това вероятно е доста бавно, така че не е нещо, което искате да правите по бързия път, ако се притеснявате за подобни неща.

person acm    schedule 17.06.2011
comment
благодаря за идеята, но мисля, че това е твърде мръсен хак за моя вкус ;) - person radman; 17.06.2011

ако искате действителния път:

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

иначе използвайте това за пълен път на файла:

path.abspath(debug.getinfo(1).short_src)
person Mohamed Dardouri    schedule 24.09.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
person WalyKu    schedule 20.10.2017

arg[0]:match('.*\\')

Ако върне нула, опитайте да промените .\*\\\ с .*/ и arg[0] с debug.getinfo(1).short_src.

Но смятам, че това е най-добрият и най-краткият начин за получаване на текущата директория.

Разбира се, можете да добавите файла, който търсите, с оператора ... Ще изглежда нещо подобно:

arg[0]:match('.*\\')..'file.lua'
person Coop Jmz    schedule 28.08.2016