1

I'm working in an environment that has approximately zero functional ui while a lua script is running. This just isn't acceptable for the script I need to write, which relies heavily on user input. The only way I've found to circumvent this is using io.popen with some rather crafty commands.

I recognize that what I'm trying to do here is strange and very much wrong, and that I've brought this upon myself, but I can't figure out what's going wrong in this code snippet:

local a = 'f'
local p = io.popen(
    'echo      -~`~-,_,- Editing '..(a == 'f' and 'foreground' or 'background')..' -~`~-,_,- > con && '.. --display text to the user
    'set /p f= Find block: > con < con && '.. --user input
    'call echo %f% &&' .. --pass f back to the lua script
    'set /p r= Replace with: > con < con && '.. --user input
    'call echo %r% &&' .. --pass r back to the lua script
    'pause < con', "r")
local f = p:read("*a") --read what was passed back, later parse it back into 2 variables
p:close()

What I expect to happen:

  1. A 'command prompt window' is displayed to the user, asking for input.
  2. The user enters 2 values.
  3. The values are echoed back to the lua script as they are entered.
  4. The values are read from the pipe and stored for later use.
  5. The command line waits for a keypress, and then closes.

What actually happens:

  1. A 'command prompt window' is displayed to the user, asking for input.
  2. The user enters a value for f.
  3. f is echoed back to the lua script.
  4. The user enters a value for r.
  5. r is echoed back to the console. (!!!)
  6. f is read from the pipe. r is not present.
  7. The command line waits for a keypress, and then closes.

This very similar code sample works just fine, but only returns 1 variable:

p = io.popen(
    'echo What do you want to do? > con && '..
    'echo G: remove girders > con && '..
    'echo F: swap foreground > con && '..
    'echo B: swap background > con && '..
    'echo U: undo all edits > con && '..
    'echo C: cancel > con && '..
    'set /p a= Choose an option: > con < con && '..
    'call echo %a%', "r")
a = string.lower(p:read("*a"):gsub("\n",""))
p:close()

What am I doing wrong, and how can I rewrite this to work for my purposes? What in the world have I unleashed, and how do I put the genie back into the bottle?

Egor Skriptunoff
  • 23,359
  • 2
  • 34
  • 64
ParadoxGate
  • 61
  • 1
  • 1
  • 5
  • Probably, this title would be better: "Interacting with user through console under consoleless host". The code should be tested under `wlua` to emulate your environment's quirks. – Egor Skriptunoff Jun 26 '15 at 17:09
  • BTW, what software installing system does have Lua scripting? – Egor Skriptunoff Jun 26 '15 at 17:39
  • I'm not actually installing anything - this is a userscript of sorts for a game. Somewhat like Minecraft's WorldEdit, except less powerful and without in-game chat (thus the CLI) or support of any kind for event-driven scripts. As it has to be installed manually by the end user, I'm avoiding external libraries and additional files as much as possible... at least for now. – ParadoxGate Jun 28 '15 at 03:37

2 Answers2

1

After a good while googling, I found this:

(
 echo some output
 echo more output
)>"Your logfile

Redirecting Output from within Batch file

I had no clue you could wrap commands like that, and I've been tinkering with the Windows CLI since I first discovered it.


local a = 'f'
local p = io.popen(
    'echo      -~`~-,_,- Editing '..(a == 'f' and 'foreground' or 'background')..' -~`~-,_,- > con && '.. --display text to the user
    '( set /p f= Find block: && '.. --user input
    'set /p r= Replace with: ) > con < con && '.. --user input
    'call echo %f% &&' .. --pass f back to the lua script
    'call echo %r% &&' .. --pass r back to the lua script
    'pause < con > con', "r")
local f = p:read("*a") --read what was passed back, later parse it back into 2 variables
p:close()

Wrapping the two set /p statements as above works - I get the expected output of f, followed by a newline, and then r, all sent back to the lua script, where they belong.

Still, if anyone can clue me in on why this was a problem in the first place, I would be very much interested in the explanation.

Community
  • 1
  • 1
ParadoxGate
  • 61
  • 1
  • 1
  • 5
0
local p = io.popen(
   -- create temporary .bat-file
   'set tmpf="%TEMP%\\TMP%RANDOM%.BAT" &&'.. 
   'cmd /c"(echo @set p=^%1&echo @set /p x= ^%p:~1,-1^%^>con&echo @call echo ^%x^%)>%tmpf%" &&'..
   -- Your main program
   'echo.      -~`~-,_,- Editing '..(a == 'f' and 'foreground' or 'background')..' -~`~-,_,- > con &&'.. --display text to the user
   'call %tmpf% "Find block:" < con &&'..  -- pass f back to the lua script
   'call %tmpf% "Replace with:" < con &&'..-- pass r back to the lua script
   -- delete temporary .bat-file
   'call del %tmpf% > con &&'.. 
   'pause < con', "r")
local f = p:read'*a'
p:close()
Egor Skriptunoff
  • 23,359
  • 2
  • 34
  • 64
  • Hmm... I don't think this will work as written, but it made me realize what the 'right' way of doing this is - just use a batch file. That'll actually eliminate a large chunk of the menu control flow from the script and make it so I only have to pop up 1 window, rather than a new one each time the user makes a choice. Also, I'll be able to use the builtin `if exists...` command, rather than the `os.rename(filename1,filename1)` hack... – ParadoxGate Jun 28 '15 at 03:32
  • @ParadoxGate - This code works as expected on my machine. Does it work on your machine? If not please describe what exactly is wrong. – Egor Skriptunoff Jun 28 '15 at 08:28