我正在尝试编写一个Ruby脚本,它在后台运行mount
命令以交互方式运行。问题是,如果我将mount命令的输入和输出重定向到管道,它不起作用。不知何故,mount似乎意识到它不是直接与stdin/stdout交谈,而是摔倒了。要么是这样,要么是影响所有交互命令的更广泛的问题;我不知道。如何从(Ruby)脚本交互地运行mount命令?
我希望能够逐行解析输出mount
,并在提问时将答案推入输入管道。这不应该是一个不合理的期望。有人可以帮忙吗?
例子:
def read_until(pipe, stop_at, timeoutsec = 10, verbose = false)
lines = []; line = ""
while result = IO.select([pipe], nil, nil, timeoutsec)
next if result.empty?
begin
c = pipe.read(1) rescue c = nil
end
break if c.nil?
line << c
break if line =~ stop_at
# Start a new line?
if line[-1] == ?\n
puts line if verbose
lines << line.strip
line = ""
end
end
return lines, line.match(stop_at)
end
cmd = "mount.ecryptfs -f /tmp/1 /tmp/2"
status = Open3::popen2e(cmd) { |i,o,t|
o.fcntl(3, 4) # Set non-blocking (this doesn't make any difference)
i.fcntl(3, 4) # Set non-blocking (this doesn't make any difference)
puts read_until(o, /some pattern/, 1, true) # Outputs [[], nil]
}
我也试过spawn
:
a, b = IO.pipe
c, d = IO.pipe
pid = spawn(cmd, :in=>a, :out=>d)
puts read_until(c, /some pattern/, 1, true) # Outputs [[], nil]
我试过subprocess
,pty
和其他解决方案的主机 - 基本上,如果它是在谷歌,我我试过了。看来如果我没有通过它真正的壳,并故意阻止,登上知道。参见:
pid = spawn(cmd, :in=>STDIN, :out=>STDOUT) # Works
pid = spawn(cmd, :in=>somepipe, :out=>STDOUT) # Blocks after first line of output, for no reason whatsoever. It's not expecting any input at this point.
我甚至尝试产卵一个真实壳(例如bash中),并通过输入管发送mount命令给它。同样的问题。
请忽略上述任何明显的错误:今晚我已经尝试了几种解决方案,所以实际的代码已被多次重写。我从记忆中写下了上述内容。
我想是这样的:有争论
- 运行mount命令,获取它的输入和输出管道流
- 等待输出管
- 回答具体问题,首先具体问题写入输入管
- 等待输出管道上的第二个具体问题
- ...等...
依此类推。
我不知道'mount'是交互式的。但是如果你的系统提供了'mount'的交互式版本,那么这可以很好地测试它的stdin/stdout是否是ttys(并且因此可能是交互式的),并且如果行为不同的话。在这种情况下,你所能做的就是尝试用一种不是交互式的命令行用法替换你的交互式用法(我宁愿这样做),或者你可以咬着酸苹果并创建一个tty来与交互'mount'命令。 – Alfe 2014-09-29 23:53:49
@Alfe:嗯....我将如何创建一个tty?我甚至不确定什么是tty!是的,mount.ecryptfs是交互式的。非交互式方法是可能的,但无法非交互式地验证密码。 – 2014-09-30 00:59:40
对于任何未来绊倒这个问题的人,请查看'PTY.spawn'和'IO.select'。感谢Alfe的提示。 – 2014-10-03 22:11:52