在运行子命令时吞咽用户输入

时间:2014-03-15 16:31:25

标签: ruby system-calls read-eval-print-loop

我正在Ruby中编写一个简单的REPL(adb的命令行包装器),我支持两种命令:

  1. 交互式命令
  2. 非交互式命令
  3. 对于2,我只想从REPL调用系统命令,在输出文本时捕获其输出,并允许用户从该命令退回到REPL。例如:

    >> logcat
    ... // log output here
    ! user hits CTRL-D
    >> // back at the prompt
    

    这是在我的程序中发生的,而不是系统shell。

    现在问题是:当logcat正在运行时,父进程(REPL)继续捕获击键,然后在命令退出时立即重放(?)它们。这意味着,如果例如命中返回几次,然后CTRL-C,它将退出子命令返回到REPL但重播所有键击,REPL不理解(如果其中一次键击发生要成为CTRL-D,它甚至会无意中退出我的程序......这显然不是我想要的。)

    现在我尝试了多种不同的执行子命令的方法(通过反引号,系统,exec),我尝试flushrewind $stdin然后再回到循环中,我试图捕获CTRL-C中断,但没有任何作用。

    我确信Ruby必须有办法:

    1. 启动子流程
    2. 将所有用户输入路由到该进程,并仅将该进程(即不是父进程)路由
    3. 返回CTRL-C上的父进程
    4. 知道如何实现这个目标吗?

1 个答案:

答案 0 :(得分:1)

您可以尝试以下内容:

Signal.trap("INT") {}         # ignore sigint in the parent
IO.popen "sort" do |io|       # run sort in a sub process
  puts io.read                # output stdout
end
Signal.trap("INT") { exit }   # restore sigint 

while true do
  puts "looping"
  sleep 1
end

如果您运行该程序,则可以输入:

$ ruby test.rb
c
d
b
^D
b
c
d
looping
looping
^C
$

$ ruby test.rb
c
d
b
^C
looping
looping
^C
$

它的工作原理是因为popen在子进程中运行命令,该进程有自己的信号处理。