4

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

  1. interactive commands
  2. non-interactive commands

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.

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.)

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.

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

  1. start a sub process
  2. route all user input to that process and only that process (i.e. not the parent process)
  3. return to parent process on CTRL-C

Any idea how to accomplish that?

1 Answer 1

2

You can try something like the following:

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
$

or

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

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

Sign up to request clarification or add additional context in comments.

2 Comments

Hm I'm not sure this does what I want. This looks like it's disabling CTRL-C on the child process? I can't do that or you'd never be able to return to the parent process?
It only disables SIGINT in the parent, try it out :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.