在运行子命令时吞下用户输入 [英] Swallowing user input while running a sub-command

查看:39
本文介绍了在运行子命令时吞下用户输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing a simple REPL (a command line wrapper for adb) in Ruby where I support two kinds of commands:

  1. 交互式命令
  2. 非交互式命令

至于 2,我只想从 REPL 调用系统命令,在输出文本时捕获其输出,并允许用户从该命令退出回 REPL.示例:

As for 2, I simply want to invoke a system command from the REPL, capture its output while it's outputting text, and allow the user to exit back into the REPL from that command. Example:

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

这发生在我的程序中,而不是系统外壳中.

This is to happen within my program, not the system shell.

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

Now the problem is: while logcat is running, the parent process (the REPL) keeps capturing keystrokes and then replays (?) them as soon as the command exits. That means, if for instance hit return a few times, then CTRL-C, it will exit out of the sub command back into the REPL but replay all the keystrokes again, which the REPL doesn't understand (if one of those keystrokes happened to be CTRL-D, it will even unintentionally exit my program... this is obviously not what I want.)

现在我已经尝试了多种不同的方式来执行子命令(通过反引号、系统、exec),我尝试了 flushrewind $stdin 在重新进入循环之前,我尝试捕获 CTRL-C 中断,但没有任何效果.

Now I have tried multiple different ways of executing the sub command (via backtick, system, exec), I tried to flush and rewind $stdin before entering back into the loop, I tried trapping the CTRL-C interrupt, but nothing works.

我确信 Ruby 中一定有办法:

I'm sure there must be a way in Ruby to:

  1. 启动子进程
  2. 将所有用户输入路由到该进程,并且仅路由到该进程(即不是父进程)
  3. 在 CTRL-C 上返回父进程

知道如何做到这一点吗?

Any idea how to accomplish that?

推荐答案

您可以尝试以下操作:

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

如果你运行程序,你可以输入:

If you run the program you can type in:

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

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

之所以有效,是因为 popen 在子进程中运行命令,该子进程有自己的信号处理.

It works because popen runs the command in a sub process, which has its own signal handling.

这篇关于在运行子命令时吞下用户输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆