How to proxy a shell process in ruby

2019-07-14 19:13发布

I'm creating a script to wrap jdb (java debugger). I essentially want to wrap this process and proxy the user interaction. So I want it to:

  • start jdb from my script
  • send the output of jdb to stdout
  • pause and wait for input when jdb does
  • when the user enters commands, pass it to jdb

At the moment I really want a pass thru to jdb. The reason for this is to initialize the process with specific parameters and potentially add more commands in the future.

Update: Here's the shell of what ended up working for me using expect:

PTY.spawn("jdb -attach 1234") do |read,write,pid|
  write.sync = true

  while (true) do
    read.expect(/\r\r\n> /) do |s|
      s = s[0].split(/\r\r\n/)
      s.pop # get rid of prompt                                                                                              

      s.each { |line| puts line }

      print '> '
      STDOUT.flush

      write.print(STDIN.gets)
    end
  end
end

标签: ruby shell
2条回答
趁早两清
2楼-- · 2019-07-14 19:46

The Ruby standard library includes expect, which is designed for just this type of problem. See the documentation for more information.

查看更多
三岁会撩人
3楼-- · 2019-07-14 19:48

Use Open3.popen3(). e.g.:

 Open3.popen3("jdb args") { |stdin, stdout, stderr|
     # stdin = jdb's input stream
     # stdout = jdb's output stream
     # stderr = jdb's stderr stream
     threads = []
     threads << Thread.new(stderr) do |terr|
         while (line = terr.gets)
            puts "stderr: #{line}"
         end
     end
     threads << Thread.new(stdout) do |terr|
         while (line = terr.gets)
            puts "stdout: #{line}"
         end
     end
     stdin.puts "blah"
     threads.each{|t| t.join()} #in order to cleanup when you're done.
 }

I've given you examples for threads, but you of course want to be responsive to what jdb is doing. The above is merely a skeleton for how you open the process and handle communication with it.

查看更多
登录 后发表回答