sum.rb
非常简单,你输入两个数字,它返回和。
# sum.rb
puts "Enter number A"
a = gets.chomp
puts "Enter number B"
b = gets.chomp
puts "sum is #{a.to_i + b.to_i}"
robot.rb
使用Open3.popen3
与sum.rb
交互。代码如下:
# robot.rb
require 'open3'
Open3.popen3('ruby sum.rb') do |stdin, stdout, stderr, wait_thr|
while line = stdout.gets
if line == "Enter number A\n"
stdin.write("10\n")
elsif line == "Enter number B\n"
stdin.write("30\n")
else
puts line
end
end
end
robot.rb
运行失败。似乎是卡在sum.rb
的gets.chomp
上。
后来我发现我必须这样写才能让它工作。你需要在输入之前按正确的顺序输入。
# robot_2.rb
require 'open3'
Open3.popen3('ruby sum.rb') do |stdin, stdout, stderr, wait_thr|
stdin.write("10\n")
stdin.write("30\n")
puts stdout.read
end
让我困惑的是:
robot_2.rb
不像与shell交互,它更像提供shell需要的东西,因为我只是知道。如果程序需要很多输入,而我们无法预测顺序,该怎么办?
1.我发现如果在sum.rb
中的每个puts
之后添加STDOUT.flush
,robot.rb
可以运行。但实际上我们不能相信sum.rb
的作者可以添加STDOUT.flush
,对吗?
谢谢你的时间!
2条答案
按热度按时间pprl5pva1#
最后找到了如何做到这一点。使用
write_nonblock
和readpartial
。你必须注意的是,stdout.readpartial
完全按照它所说的那样做,这意味着你将不得不聚集数据并通过查找换行符来执行gets
。对于寻求更通用的交互性(例如ssh交互)的用户,您可能希望创建单独的线程来聚合stdout和触发stdin。
顺便说一句,这不是非常线程安全的。这只是一个未优化的,但功能的解决方案,我发现,希望在未来得到改善。
1sbrub3j2#
我尝试了一下@jeff-hykin的答案。所以,主要的一点是以非阻塞模式发送来自
sum.rb
的数据,即使用STDOUT.write_nonblock
:--注意
STDOUT.write_nonblock
调用中的\n
。它分隔字符串/行,这些字符串/行是用robot.rb
中的gets
“get string”读取的。然后robot.rb
可以保持不变。我只会在条件中添加strip
:Ruby版本是3.0.2。