ruby - system ("git push 2>&1") 工作正常,但 %x(git push 2>&1) 挂起。为什么?

标签 ruby git shell ssh

我正在使用 Ruby。我想弄清楚为什么 bundler 的 rake release 卡在 git push 步骤上,也是 discussed inconclusively here .

我已经将范围缩小到挂起的这行代码:

    `git push 2>&1`

我可以通过在 IRB 中运行同一行代码来重现该问题。

神秘的是底层的 git push 实际上执行了,但出于某种原因,Ruby 从未收到返回状态。它只是无限期地等待子进程。

检查进程列表显示子进程具有 Z+(僵尸?)状态:

    UID   PID  PPID   C STIME   TTY           TIME CMD   USER       PGID   SESS JOBC STAT   TT 
    501 23397  3757   0  1:44PM ttys001    0:00.54 irb   mbrictson 23397      0    1 S+   s001 
    501 26035 23397   0  2:06PM ttys001    0:00.00 (sh)  mbrictson 23397      0    1 Z+   s001 

显然,git push 运行只是在我的 shell 中查找。只是在使用它挂起的反引号通过 Ruby 调用它时。

此外,这工作正常:

    system("git push 2>&1") # => true

这(即没有输出重定向)也能正常工作!

    `git push` # => "Everything up-to-date"

部分问题显然是在我的 ~/.ssh/config 中的 ControlMaster auto。当执行 git push 时,这会导致在后台生成一个新的控制连接进程。也许 %x(git push 2>&1) 正在等待这个后台进程退出?如果我在我的 SSH 配置中禁用 ControlMaster,这实际上可以解决问题。

不过,这让我很困扰。我宁愿不必仅仅为了让 Ruby 的反引号运算符满意而禁用 ControlMaster。

谁能解释一下:

  • 为什么 %x() 挂起而 system() 没有挂起?
  • 为什么删除 2>&1 会有所不同?

这是在带有 Ruby 2.2.0 的 Mac OS X Yosemite 上运行的。

最佳答案

想通了:

Why does %x() hang but system() does not?

%x() 等待完全读取子进程的输出; system() 不关心输出。

According to this bug report , OpenSSH 中的 ControlPersist 设置导致 stderr 在主连接的生命周期内保持打开状态。在我的 SSH 配置中,我有 ControlPersist 5m,果然,%x() 在最终完成之前恰好挂起 5 分钟。

这不会影响 system(),因为系统不会等待输出。

Why does removing 2>&1 make a difference?

如上所述,SSH 主连接使 stderr 保持打开状态。它显然关闭了标准输出。由于 stdout 已关闭,%x(git push) 立即完成,因为在 stdout 上没有什么可等待的。当 2>&1 添加到命令时,这会导致 stderr 被重定向到 stdout。由于 stderr 被主连接保持打开状态,这反过来导致 stdout 保持打开状态。 %x 等待标准输出并挂起。

不幸的是,OpenSSH 的这种行为没有任何改变的迹象,因此除了禁用 ControlPersist 之外没有令人满意的解决方案。

关于ruby - system ("git push 2>&1") 工作正常,但 %x(git push 2>&1) 挂起。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28821507/

相关文章:

ruby-on-rails - RVM 使用了错误的 ruby​​ 版本

git - Visual Studio Team Services 上的文件不同步(Git 存储库)

Git:如何获取特定修订版本之间的文件

ios - 为 iOS 推送通知导入 SSL 证书会阻止其他开发人员处理该项目吗?

shell - Sublime Text 2 服务

ruby-on-rails - Ruby on Rails 能否利用英特尔的多核处理能力?

ruby - 如何在 Ruby 中使用散列键进行这些字符串替换?

bash - 如何从命令行重新加载 .bash_profile

linux - 如何在 linux/unix 下执行此操作?

ruby-on-rails - 引用 Ruby 嵌套类的表示法