I'm trying to create a program that runs a shell on the background and sends user commands to it for execution and return the result. This is the code:
--note: this runs on windows but I assume replacing "cmd" with "sh" it can run on linux as well
exe,err=io.popen("cmd > stdout.txt 2> stderr.txt");
if not exe then
print("Could not run command. Error: "..err)
return
else
print("Command run successfully... ready!")
end
stdout,err=io.open("stdout.txt","r")
if not stdout then print("Could not open stdout: "..err) return end
stderr,err=io.open("stderr.txt","r")
if not stdout then print("Could not open stderr: "..err) return end
function execute(str)
exe:write(str)
return stdout:read("*all") or stderr:read("*all") or "nil"
end
repeat
print("COMMAND: ")
userinput=io.read("*line")
print("You entered: '"..userinput.."'")
if userinput=="" then print "Empty line! Exiting program..." break end
print("Result: "..execute(userinput))
until true
print "Closing..."
execute("exit")
print "1"
exe:close()
print "2"
stdout:close()
print "3"
stderr:close()
print "Finished!"
Problem: when exiting the program, it hangs on exe:close()
call. The execution loop behaves weird too (sometimes I have to press enter several times for userinput=io.read("*line")
to work.
I googled to see if file:close() also works on the file handle that is the result of io.popen() but didn't find anything. But that call doesn't fail. It just hangs up. In other words the output of the program is like this:
Command run successfully... ready!
COMMAND:
dir
dir
You entered: 'dirdir'
Result: Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\lua>
C:\lua>
C:\lua>
Closing...
1
Lua only depends on ANSI C features. Therefore io.popen
uses the popen(3)
function. Quoting from it's manual:
Since a pipe is by definition unidirectional, the type argument may specify only reading or writing, not both; the resulting stream is correspondingly read-only or write-only.
You attempt to solve this limitation by redirecting the output to a file and simultaneously open that file and read from it after executing a command. However, in this case you may run into problems with output buffering - I think this is what you are experiencing.
Instead of trying to work around io.popen
, you may try out the Lua Ex API (wiki page here), which provides an alternative process spawning API and allows you to do things like this:
-- popen2(), from http://lua-users.org/wiki/ExtensionProposal
function popen2(...)
local in_rd, in_wr = io.pipe()
local out_rd, out_wr = io.pipe()
local proc, err = os.spawn{stdin = in_rd, stdout = out_wr, ...}
in_rd:close(); out_wr:close()
if not proc then
in_wr:close(); out_rd:close()
return proc, err
end
return proc, out_rd, in_wr
end
-- usage:
local p, i, o = assert(popen2("wc", "-w"))
o:write("Hello world"); o:close()
print(i:read"*l"); i:close()
p:wait()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With