交互式popen()函数 Lua调用

我正在尝试创建一个程序,在后台运行shell,并将用户输入的命令发送给它以执行并返回结果。这是代码:

--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!"

问题:退出程序时,它挂在exe:close()调用上。执行循环也表现奇怪(有时需要多次按Enter才能使userinput=io.read(“* line”)起作用)。

我谷歌搜索以查看文件:close()是否也适用于io.popen()结果的文件句柄,但没有找到任何结果。但是该调用并不失败。它只是挂起。换句话说,程序的输出如下所示:

Command run successfully... ready!
COMMAND:
dir

dir
You entered: 'dirdir'
Result: Microsoft Windows [Version 6.1.7601]
版权所有(c)2009年Microsoft Corporation。 保留所有权利。

C:\ lua>
C:\ lua>
C:\ lua>
关闭...
1

原文链接 https://stackoverflow.com/questions/8716527

点赞
stackoverflow用户221509
stackoverflow用户221509

Lua 仅依赖于 ANSI C 特性。因此 io.popen 使用 popen(3) 函数。引用文档如下:

由于管道定义为单向的,类型参数只能指定读取或写入两者之一;得到的流相应地是只读或只写的。

你尝试通过重定向输出到文件并同时在执行命令后打开该文件并从中读取来解决这个限制。然而,在这种情况下,你可能会遇到输出缓冲问题 - 我认为这就是你所遇到的问题。

与其试图绕过 io.popen,不如尝试使用 Lua Ex API维基页面在这里),该 API 提供了一种替代的进程生成 API,使你可以像这样做:

-- 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()
2012-01-03 22:43:01