Search code examples
luadownloadevalread-eval-print-loop

Oneliner to load Lua script from online (Gist) and run in current context


I have a lua REPL, and would like to run a lua script file stored as plain text at HTTPS://URL. I understand os.execute() can run OS commands so we can use curl etc. to grab the script then load(). Is that something possible to do in lua REPL with a single line?


Solution

  • Note: If you're going to run source code directly from the web, use https at least, to avoid easy MitM attacks.

    To give this question an answer, since Egor will probably not post it as such:

    (loadstring or load)(io.popen("wget -qO- https://i.imgur.com/91HtaFp.gif"):read"*a")()
    

    For why this prints Hello world:

    loadstring or load is to be compatible with different Lua versions, as the functions loadstring and load were merged at some point (5.2 I believe). io.popen executes its first argument in the shell and returns a file pointer to its stdout.

    The "gif" from Egor is not really a GIF (open this in your browser: view-source:https://i.imgur.com/91HtaFp.gif) but a plain text file that contains this text:

    GIF89a=GIF89a
    print'Hello world'
    

    Basically a GIF starts with GIF89a and the =GIF89a afterwards is just to produce valid Lua, meaning you don't have to use imgur or gifs, you can just as well use raw gists or github.

    Now, it's rather unlikely that os.execute is available in a sandbox when io.popen is not, but if it is, you can achieve a one-liner (though drastically longer) using os.execute and temporary files

    Lets first write this out because in a single line it will be a bit complex:

    (function(u,f)
        -- get a temp file name, Windows prefixes those with a \, so remove that
        f=f or os.tmpname():gsub('^\\','')
        -- run curl, make it output into our temp file
        os.execute(('curl -s "%s" -o "%s"'):format(u,f))
        -- load/run temp file
        loadfile(f)()
        os.remove(f)
    end)("https://i.imgur.com/91HtaFp.gif");
    

    And you can easily condense that into a single line by removing comments, tabs and newlines:

    (function(u,f)f=f or os.tmpname():gsub('^\\','')os.execute(('curl -s "%s" -o "%s"'):format(u,f))loadfile(f)()os.remove(f)end)("https://i.imgur.com/91HtaFp.gif");