интерактивный popen () вызов Lua - PullRequest
4 голосов
/ 03 января 2012

Я пытаюсь создать программу, которая запускает оболочку в фоновом режиме и отправляет ей пользовательские команды для выполнения и возвращает результат. Это код:

--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() вызов. Цикл выполнения также ведет себя странно (иногда мне приходится нажимать клавишу ввода несколько раз, чтобы userinput=io.read("*line") заработал.

Я гуглил, чтобы посмотреть, работает ли file: close () с дескриптором файла, который является результатом io.popen (), но ничего не нашел. Но этот звонок не провалится. Это просто зависает. Другими словами, вывод программы такой:

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

1 Ответ

7 голосов
/ 04 января 2012

Lua зависит только от функций ANSI C.Поэтому io.popen использует функцию popen(3).Цитирование из его руководства:

Поскольку канал по определению является однонаправленным, аргумент типа может указывать только чтение или запись, но не оба;результирующий поток, соответственно, предназначен только для чтения или только для записи.

Вы пытаетесь устранить это ограничение, перенаправляя вывод в файл и одновременно открывая этот файл и читая из него после выполнения команды.Однако в этом случае вы можете столкнуться с проблемами с буферизацией вывода - я думаю, что это то, что вы испытываете.

Вместо того, чтобы пытаться обойти io.popen, вы можете попробовать Lua Ex 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...