Ruby Runy Open3.popen3从命令行向子流程输入输入

Ruby Runy Open3.popen3从命令行向子流程输入输入,ruby,shell,command-line,stdin,popen3,Ruby,Shell,Command Line,Stdin,Popen3,目标:我正在用ruby编写一个工作流命令行程序,它在UNIX shell上顺序执行其他程序,其中一些程序需要用户输入 问题:虽然我可以成功地处理stdout和stderr,但由于有了这样的帮助,我仍然无法捕获用户输入并通过命令行将其传递到子进程中。代码如下: 方法 模块CMD def运行(cmd和block) Open3.popen3(cmd)do | stdin、stdout、stderr、thread| Thread.new do#STDOUT 直到(line=stdout.get).nil

目标:我正在用ruby编写一个工作流命令行程序,它在UNIX shell上顺序执行其他程序,其中一些程序需要用户输入

问题:虽然我可以成功地处理
stdout
stderr
,但由于有了这样的帮助,我仍然无法捕获用户输入并通过命令行将其传递到子进程中。代码如下:

方法

模块CMD
def运行(cmd和block)
Open3.popen3(cmd)do | stdin、stdout、stderr、thread|
Thread.new do#STDOUT
直到(line=stdout.get).nil?做
如果给定块_,则产生零、线、零、螺纹?
结束
结束
Thread.new do#STDERR
直到(line=stderr.get).nil?做
如果给定块,则产生零、零、线、螺纹?
结束
结束
Thread.new do#STDIN
# ????? 如何处理
结束
线程连接
结束
结束
结束
调用方法

此示例调用shell命令
units
,该命令提示用户输入测量单位,然后提示输入要转换为的单位。这就是它在外壳中的外观

>单位
586个单元,56个前缀#stdout
您有:1升#用户输入
您需要:加仑#用户输入
*0.26417205#标准值
/3.7854118#标准件
当我从我的程序运行它时,我希望能够以完全相同的方式与它交互

unix\u cmd='units'
运行unix_cmd do|stdin、stdout、stderr、thread|
如果stdout,则放入“stdout#{stdout.strip}”
如果是stderr,则将“stderr#{stderr.strip}”置于
#我不确定我将如何允许用户
#在这里与STDIN互动?
结束
注意:通过这种方式调用
run
方法,用户可以解析输出、控制流程和添加自定义日志记录

从我收集的关于STDIN的信息来看,下面的代码片段与我对如何处理STDIN的理解一样接近,我的知识显然存在一些差距,因为我仍然不确定如何将其集成到上面的
run
方法中,并将输入传递到子进程中

#STDIN:用ruby声明的常量
#stdin:Open3.popen3中声明的参数
新做的
#阅读控制台上的每一行
标准每行do|
将“STDIN:#{line}”放入#打印捕获的输入
stdin.write line#将输入写入stdin
stdin.sync#将输入同步到子进程中
如果行==“\n”则中断
结束
结束

摘要:我希望了解如何通过
Open3.popen3
方法处理来自命令行的用户输入,以便允许用户将数据输入到从我的程序调用的各种子命令序列中。

以下是一些应该有效的方法:

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

      t = Thread.new { loop { stdin.puts gets } }

      thread.join
      t.kill
    end
  end
end 

我刚刚在您原来的
run
方法中添加了两行代码:
t=Thread.new{loop{stdin.puts gets}
,和
t.kill

在大量阅读了stdin以及一些很好的旧的尝试和错误之后,我发现了一个与之不同的实现,但有一些细微的差异

需要“open3”
模块Cmd
def运行(cmd和block)
Open3.popen3(cmd)do | stdin、stdout、stderr、thread|
#我们只需要检查是否提供了一次块
#而不是像我们所做的那样循环的每个周期
#在原来的问题中。
如果给出了block_?
新做的
直到(line=stdout.get).nil?做
屈服线,零,螺纹
结束
结束
新做的
直到(line=stderr.get).nil?做
零屈服、线屈服、线屈服
结束
结束
结束
#$stdin.get从控制台读取数据
#
#stdin.puts写入子进程
#
#当我活着的时候?意味着我们继续前进
#读取输入直到子进程结束
新做的
stdin.put$stdin.get而thread.alive?
结束
线程连接
结束
结束
结束
包括命令
这样调用方法:

run./test_script.sh'do |标准输出,标准输出,线程|
将“#{thread.pid}stdout:#{stdout}”置于stdout
将“#{thread.pid}stderr:#{stderr}”放入stderr
结束
其中
test_script.sh
如下所示:

echo“发送到标准输出的消息”
>&2回显“发送至STDERR的消息”
echo“输入用户名:”
读取用户名
回显“输入问候语”
读问候语
echo“$greeting$username”
出口0
生成以下成功输出:

25380标准输出:发送给标准输出的消息
25380标准输出:输入用户名:
25380 stderr:发送给stderr的消息
>韦恩
25380标准输出:输入问候语
>你好
你好,韦恩
注意:您会注意到stdout和stderr没有按顺序出现,这是一个我尚未解决的限制


如果你有兴趣了解更多关于stdin的信息,那么值得阅读以下问题的答案-

我也想知道如何做到这一点。这似乎不起作用。恐怕,我通过调用方法
CMD.run'units'
对其进行了测试。你成功地让它工作了吗?是的,这对我来说很有效。注意,我使用的是Ruby 2.1.5。