2011-06-17 12 views
16

Me pregunto si hay una forma de obtener la ruta al archivo de script lua actualmente en ejecución?Obtiene que contiene la ruta del archivo lua

Este no es específicamente el directorio de trabajo actual, que podría ser completamente diferente. Sé que luafilesystem me permitirá obtener el directorio de trabajo actual, pero no parece poder decir el archivo de script de ejecución actual.

Gracias

EDIT: No estoy corriendo desde el intérprete de línea de comandos estándar, Estoy ejecutando las secuencias de comandos desde un binario de C++ a través de luabind.

Respuesta

6

Si la secuencia de comandos Lua está siendo ejecutada por el intérprete de línea de comandos estándar, intente con arg[0].

+0

Si hice dofile (subarchivo) dentro del original, ¿funcionaría este método para obtener la ruta del subarchivo? – radman

+3

@radman: no. Además, 'dofile' usa cualquier ruta que se encuentre y, por lo tanto, las rutas relativas son relativas al directorio de trabajo actual del proceso. Si desea rastrear archivos entregados a 'dofile', puede redefinirlo. – lhf

+0

y el usuario también podría usar loadfile y luego ejecutar el archivo cargado como una llamada de función, puede que tenga que redefinir también el archivo de carga –

3

Como LHF dice:

~ e$ echo "print(arg[0])" > test.lua 
~ e$ lua test.lua 
test.lua 
~ e$ cd/
/e$ lua ~/test.lua 
/Users/e/test.lua 
/e$ 

Aquí está la misma información mediante el mecanismo de 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$ 

Este servicio está disponible a partir de la API C lua_getinfo

0

Tenga una mirada en el Lua biblioteca de depuración, que es parte de la distribución estándar de Lua. Puede utilizar debug.getinfo para encontrar el archivo actual, o el archivo de hasta N tramas en la pila de llamadas:

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

Tenga en cuenta que esto es probablemente bastante lento, por lo que no es algo que desea hacer en el camino rápido si estás preocupado por tales cosas.

+0

gracias por la idea, pero creo que es demasiado hack sucio para mi gusto;) – radman

3

La única forma confiable de obtener lo que desea es reemplazar dofile con su propia versión de esta función. Incluso el método debug.getinfo no funcionará, ya que solo devolverá la cadena pasada a dofile. Si esa fue una ruta relativa, no tiene idea de cómo se convirtió a una ruta absoluta.

El código de anulación sería algo como esto:

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. 

Las funciones extractFilePath, isRelativePath y currentDir no son funciones Lua; tendrás que escribirlos tú mismo. La función extractFilePath extrae una cadena de ruta de un nombre de archivo. isRelativePath toma una ruta y devuelve si la ruta dada es una ruta de acceso relativa. currentDir simplemente devuelve el directorio actual. Además, deberá usar "\" en lugar de "/" en máquinas con Windows.

Esta función almacena la ruta en un global llamado path. Puedes cambiar eso a lo que quieras.

+1

fyi, también puedes usar '/' para las rutas de Windows. – jpjacobs

+0

también loadfile debe anularse –

15

Ésta es una forma más elegante:

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

print(script_path()) 
+0

Si el script se ejecuta sin una ruta, como 'lua myscript' (en el que lua asume que significa'./Myscript'), esta función devuelve 'nil'. Sugiero usar 'return str: match (" (. * /) ") O". "' –

+0

Para que esto funcione en Windows, reemplace 'str: match (" (. * /) ")' Con 'str: match ("(. * [/ \\])") ' – tversteeg

1
miradas

forma más corta que he encontrado de esta manera:

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

Índice 1, 2- otro - depende de qué función en la pila de llamadas que quiero hacer una consulta 1 se llamó última función (donde estás).Si se está ejecutando en el contexto global, entonces probablemente 2 es más apropiado (no han probado por mí mismo)

+0

' arg [0]: match ("@? (. * /)") 'Funciona para mí al ejecutar desde la consola. – Tim

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

Si devuelve nil intente cambiar el .\*\\\ con .*/ y arg[0] con debug.getinfo(1).short_src.

Pero considero que esta es la mejor y más breve forma de obtener el directorio actual.

Por supuesto, puede agregar el archivo que está buscando con el operador ... Se verá algo como esto:

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

si desea que la ruta real:

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

persona use esto para ruta completa del archivo:

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

Si desea que el camino real que incluye el nombre del archivo, solo use la siguiente

pathWithFilename=io.popen("cd"):read'*all' 
print(pathWithFilename) 

Probado en Windows.

Explicación:

io.popen - envía comandos a la línea de comandos, y devuelve el resultado.

"cd" - cuando ingresa esto en cmd, obtiene la ruta actual como salida.

:read'*all' - como io.popen devuelve un objeto similar a un archivo, puede leerlo con el mismo tipo de comandos. Esto lee toda la salida.


Si alguien requiere la ruta 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

He escrito una función getScriptDir que utiliza la información de depuración al igual que algunas otras personas han sugerido, pero éste se va a trabajar cada vez (por lo menos en Windows). Pero la cosa es que hay bastantes líneas de código ya que usa otra función string.cut que he creado, que separa una cadena de cada patrón dado, y la coloca en una tabla.

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 

Nota: si desea utilizar esta función en otro sistema operativo que no sea Windows, usted tiene que cambiar el io.popen("echo %cd%") en la línea 15 a cualquier comando que da presentes directorio de trabajo en su sistema operativo, por ejemplo, io.popen("pwd") para Linux, y pwd2:sub(2,3) == ":/" en la línea a lo que represente el directorio raíz en su sistema operativo, p. Ej. pwd2:sub(1,1) == "/" para Linux.

Nota 2: si no se proporciona la variable source a la función a través de debug.getinfo(1).source cuando se llama a ella, entonces se devuelve la ruta hasta el directorio del archivo que contiene esta función .Por lo tanto, si desea obtener el directorio de un archivo que llamó a través del dofile o loadfile, tendrá que darle la fuente, como este: getScriptDir(debug.getinfo(1).source).

Cuestiones relacionadas