ruby - Ruby 退出后,STDIN.read_nonblock 会扰乱其他程序

标签 ruby linux shell terminal

我正在用 Ruby 编写一个交互式终端程序,它有时会运行 STDIN.read_nonblock(256) 来刷新所有缓冲的用户输入。

运行我的 Ruby 程序后,如果我在同一个终端和 shell 中运行 git add -p(另一个交互式程序),那么 git 会发生故障:它不会花任何时间等待用户输入而是立即显示所有提示然后退出。

这是一个 shell session ,展示了我如何使用 Ubuntu 18.04、Ruby 2.6.3 和 git 2.17.1 重现它:

$ mkdir testrepo && cd testrepo && git init .
Initialized empty Git repository in /home/david/tmp/testrepo/.git/
$ touch foo.txt
$ git add foo.txt
$ echo hi > foo.txt
$ git add -p  # works fine
diff --git a/foo.txt b/foo.txt
index e69de29..45b983b 100644
--- a/foo.txt
+++ b/foo.txt
@@ -0,0 +1 @@
+hi
Stage this hunk [y,n,q,a,d,e,?]? q

$ ruby -v -e 'STDIN.read_nonblock(256)'
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
Traceback (most recent call last):
    2: from -e:1:in `<main>'
    1: from <internal:prelude>:73:in `read_nonblock'
<internal:prelude>:73:in `__read_nonblock': Resource temporarily unavailable - read would block (IO::EAGAINWaitReadable)
$ git add -p  # bad: exits before waiting for input
diff --git a/foo.txt b/foo.txt
index e69de29..45b983b 100644
--- a/foo.txt
+++ b/foo.txt
@@ -0,0 +1 @@
+hi
Stage this hunk [y,n,q,a,d,e,?]? 
$ git --version
git version 2.17.1

我可以在我的 Ruby 程序中加入任何解决方法来防止这种情况发生吗? (我也对任何可能发生的事情感兴趣。)

顺便说一下,我注意到可以通过运行 bash 启动一个新的 shell,然后键入 Ctrl+D 退出那个新的 shell 来修复困惑的终端。

最佳答案

除了您自己的答案之外,还有一种方法可以将描述符上的 O_NONBLOCK 重置为阻塞。这也解决了这个问题:

require 'fcntl'

flags = STDIN.fcntl(Fcntl::F_GETFL, 0)
STDIN.fcntl(Fcntl::F_SETFL, flags & ~Fcntl::O_NONBLOCK)

您必须在 ensure block 中运行此代码,因为 read_nonblock 在任何情况下都不会重置标志。

关于ruby - Ruby 退出后,STDIN.read_nonblock 会扰乱其他程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57170899/

相关文章:

linux - Linux 模拟器 "Cannot execute binary"错误

LINUX:如何软链接(soft link)所有子目录中的特定文件

linux - DPDK解绑后如何领取网卡?

mysql - 如何在不使用mysql命令的情况下在linux中比较两个MySQL sql文件

bash - 如何确定文件是否不可在 bash 脚本中执行

ruby - 如何迭代到 Ruby 中的下一个元素?

ruby-on-rails - Ruby - 访问查询响应的正确方法

ruby - 如何将嵌套的哈希值收集到 ruby​​ 中的数组中?

ruby-on-rails - Rails 应用程序显示文件而不是显示应用程序

linux - 如何将命令执行器覆盖到 ~/bin my own 下的新版本 Git 而不是旧的/usr/bin/git