目标:我正在用 ruby 编写一个工作流命令行程序,该程序在 UNIX shell 上按顺序执行其他程序,其中一些程序需要用户输入。
问题:虽然我可以成功地处理stdout
和stderr
感谢Nick Charlton的这篇有用的博客文章,但是我仍然坚持捕获用户输入并通过命令行将其传递到子进程中。代码如下:
方法
module CMD
def run(cmd, &block)
Open3.popen3(cmd) do |stdin, stdout, stderr, thread|
Thread.new do # STDOUT
until (line = stdout.gets).nil? do
yield nil, line, nil, thread if block_given?
end
end
Thread.new do # STDERR
until (line = stderr.gets).nil? do
yield nil, nil, line, thread if block_given?
end
end
Thread.new do # STDIN
# ????? How to handle
end
thread.join
end
end
end
调用方法
此示例调用 shell 命令,该命令units
提示用户输入测量单位,然后提示输入要转换的单位。这就是它在外壳中的样子
> units
586 units, 56 prefixes # stdout
You have: 1 litre # user input
You want: gallons # user input
* 0.26417205 # stdout
/ 3.7854118 # stdout
当我从我的程序中运行它时,我希望能够以完全相同的方式与之交互。
unix_cmd = 'units'
run unix_cmd do | stdin, stdout, stderr, thread|
puts "stdout #{stdout.strip}" if stdout
puts "stderr #{stderr.strip}" if stderr
# I'm unsure how I would allow the user to
# interact with STDIN here?
end
注意:以这种方式调用该run
方法允许用户能够解析输出、控制流程并添加自定义日志记录。
根据我收集到的关于 STDIN 的信息,下面的代码片段与我对如何处理 STDIN 的理解一样接近,但我的知识显然存在一些差距,因为我仍然不确定如何将其集成到我run
上面的方法中,并且将输入传递给子进程。
# STDIN: Constant declared in ruby
# stdin: Parameter declared in Open3.popen3
Thread.new do
# Read each line from the console
STDIN.each_line do |line|
puts "STDIN: #{line}" # print captured input
stdin.write line # write input into stdin
stdin.sync # sync the input into the sub process
break if line == "\n"
end
end
摘要:我希望了解如何通过该Open3.popen3
方法处理来自命令行的用户输入,以便我可以允许用户将数据输入到从我的程序调用的各种子命令序列中。