【发布时间】:2019-12-18 11:25:02
【问题描述】:
我想要达到的目标:
- 从 Ruby 进程生成子进程
- 子进程应正常打印回终端。 “正常”是指该过程不应错过颜色输出,或忽略用户输入 (STDIN)。
- 对于该子流程,捕获 STDOUT/STDERR(联合)例如到子进程死亡后可以访问的字符串变量。转义字符等等。
通过传递不同的 IO 管道可以捕获 STDOUT/STDERR,但是子进程可以检测到它不在 tty 中。例如git log 不会打印影响文本颜色的字符,也不会使用它的寻呼机。
使用pty 启动进程本质上是“欺骗”子进程,使其认为它是由用户启动的。据我所知,这正是我想要的,结果基本上符合所有条件。
我测试解决方案是否符合我的需求的一般测试是:
-
ls -al是否正常运行? -
vim是否正常运行? -
irb是否正常运行?
以下 Ruby 代码可以检查以上所有内容:
to_execute = "vim"
output = ""
require 'pty'
require 'io/console'
master, slave = PTY.open
slave.raw!
pid = ::Process.spawn(to_execute, :in => STDIN, [:out, :err] => slave)
slave.close
master.winsize = $stdout.winsize
Signal.trap(:WINCH) { master.winsize = $stdout.winsize }
Signal.trap(:SIGINT) { ::Process.kill("INT", pid) }
master.each_char do |char|
STDOUT.print char
output.concat(char)
end
::Process.wait(pid)
master.close
这在大多数情况下都有效,但事实证明它并不完美。出于某种原因,某些应用程序似乎无法切换到raw 状态。尽管vim 工作得很好,但结果证明neovim 没有。起初我认为这是 neovim 中的一个错误,但后来我能够使用 Rust 语言的 Termion crate 重现该问题。
通过在执行前手动设置为 raw (IO.console.raw!),neovim 之类的应用程序的行为符合预期,但irb 之类的应用程序则不然。
奇怪地在 Python 中生成 另一个 pty,在这个 pty 内,允许应用程序按预期工作(使用 python -c 'import pty; pty.spawn("/usr/local/bin/nvim")')。这显然不是一个真正的解决方案,但仍然很有趣。
对于我的实际问题,我想我正在寻求任何帮助来解决奇怪的raw 问题,或者说如果我完全误解了 tty/pty,我应该在哪里/如何看待问题的任何不同方向.
【问题讨论】:
标签: ruby io subprocess pty