【问题标题】:system("git push 2>&1") works fine, but %x(git push 2>&1) hangs. Why?system("git push 2>&1") 工作正常,但 %x(git push 2>&1) 挂起。为什么?
【发布时间】:2015-05-03 11:54:54
【问题描述】:

我正在使用 Ruby。我试图弄清楚为什么捆绑器的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 上。

【问题讨论】:

  • %x 版本捕获输出,system 版本不捕获。我不确定这是否会影响git,它可能会因某种原因提出阻碍流程的问题。如果您想知道发生了什么,最好使用popen3 以获得最大控制权。
  • 命令运行时git有没有事有关系吗?
  • @EtanReisner 它似乎与 git 正在做的事情没有任何关系。当有要推送的提交并且所有内容都是最新的时,我会看到问题。
  • ssh 进程的 fd 在挂起时是什么样子的?在等待输出时,额外的过程可能会混淆反引号(正如 tadman 指出的那样,system 不会等待)。
  • @tadman 我不认为 git 在问问题;就像我说的,删除ControlMaster 似乎是决定因素。出于好奇,我希望找出根本原因。如果是常见问题,也许bundler会接受一个PR来切换到popen3。

标签: ruby git shell ssh


【解决方案1】:

想通了:

为什么 %x() 挂起,而 system() 没有?

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

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

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

为什么删除 2>&1 会有所不同?

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

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

【讨论】:

    猜你喜欢
    • 2013-03-10
    • 2020-01-10
    • 2017-11-14
    • 2013-09-04
    • 2012-03-06
    • 1970-01-01
    • 2015-08-28
    • 2018-06-29
    • 2010-12-01
    相关资源
    最近更新 更多