ruby – Runy Open3.popen3从命令行输入子进程的输入
目标:我正在
ruby中编写一个工作流命令行程序,它顺序执行UNIX shell上的其他程序,其中一些程序需要用户输入输入.
问题:虽然我可以成功处理stdout和stderr,感谢这个有用的blog post by 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,thread if block_given? end end Thread.new do # STDIN # ????? How to handle end thread.join end end end 调用方法 此示例调用shell命令单元,提示用户输入度量单位,然后提示要转换为单位.这就是它在shell中的样子 > 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,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方法从命令行处理用户输入,以便我可以允许用户将数据输入到从我的程序调用的各种子命令序列中. 解决方法
经过大量关于STDIN的阅读以及一些好的旧试验和错误后,我发现了一个与
Charles Finkel’s
answer不同的实现,但有一些细微的差别.
require "open3" module Cmd def run(cmd,thread| # We only need to check if the block is provided once # rather than every cycle of the loop as we were doing # in the original question. if block_given? Thread.new do until (line = stdout.gets).nil? do yield line,thread end end Thread.new do until (line = stderr.gets).nil? do yield nil,thread end end end # $stdin.gets reads from the console # # stdin.puts writes to child process # # while thread.alive? means that we keep on # reading input until the child process ends Thread.new do stdin.puts $stdin.gets while thread.alive? end thread.join end end end include Cmd 像这样调用方法: run './test_script.sh' do | stdout,thread| puts "#{thread.pid} stdout: #{stdout}" if stdout puts "#{thread.pid} stderr: #{stderr}" if stderr end test_script.sh的位置如下: echo "Message to STDOUT" >&2 echo "Message to STDERR" echo "enter username: " read username echo "enter a greeting" read greeting echo "$greeting $username" exit 0 产生以下成功输出: 25380 stdout: Message to STDOUT 25380 stdout: enter username: 25380 stderr: Message to STDERR > Wayne 25380 stdout: enter a greeting > Hello 25380 stdout: Hello Wayne 注意:您会注意到stdout和stderr没有按顺序出现,这是我尚未解决的限制. 如果您有兴趣了解有关stdin的更多信息,那么值得阅读以下问题的答案 – What is the difference between STDIN and $stdin in Ruby? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |