Ruby Kernel#` 调用 xclip irb 挂起

toctan · 2013年10月08日 · 最后由 toctan 回复于 2013年10月09日 · 2493 次阅读

用 Linux 的同学们帮忙打开 irb 或者 pry 试下下面两行代码:

2.0.0p247 > system "xclip .bashrc"
 => true 
2.0.0p247 > `xclip .bashrc`
# irb hangs!

完全想不通 irb 为什么会挂起啊,查了下文档, Kernel#`Kernel#system 都是在 subshell 里跑命令,只是前者返回标准输出结果,后者返回 true, falsenil

上面是让 xclip 的标准输出到 irb 了 下面是建立了管道,要等到 xclip 输出 EOF 才能返回

#1 楼 @luikore

不对啊, xclip 为什么会建立管道,只是读取.bashrc的内容到primary selection, 况且这时候摁 Ctrl-d 也没用

哦,早上起来换到 root 再试了一下,这次xclip .bashrc 正常返回了,但是:

irb(main):002:0> require 'benchmark'
=> true
irb(main):003:0> puts Benchmark.measure { system "xclip .bashrc" }
  0.000000   0.000000   0.000000 (  0.007043)
=> nil
irb(main):004:0> puts Benchmark.measure { `xclip .bashrc` }
  0.000000   0.000000   0.010000 ( 19.856729)
=> nil

可以看看 Benchmark.measure 的源码,可能使用了 Thread.new

#3 楼 @sevk 应该和 Benchmark.measure 无关,因为 `xclip .bashrc` 慢了快 20 秒,不用 Benchmark 也能明显的感觉到

果然啊,我这里要 24 秒

[8] pry(main)> puts Benchmark.measure { `xclip .vimrc` }
  0.000000   0.000000   0.000000 ( 24.320067)
=> nil

#2 楼 @toctan

`` 就是接受进程的 stdout 输出,并变成字符串。需要等 EOF.

system 在起的那个进程退出时就自然退出了。

而等待 stdout 退出,需要等到它的所有子进程都退出。

把下面代码存为 xclip2, 自己看看 system "./xclip2"`./xclip2` 的区别吧

#! /usr/bin/env ruby
fork do
  sleep 3
  print ''
end

你的调用明显是不需要其输出结果的,用 `` 就白白等待 EOF 了。

#6 楼 @luikore 我懂你的意思了,再加上 Stackoverflow 上的另一条回答就能够解释为什么`xclip .bashrc` 多花这么多时间了:

$ xclip -verbose .bashrc
Connected to X server.
Using UTF8_STRING.
Reading .bashrc...
Waiting for selection requests, Control-C to quit

问题在于 xclip 不会自己 terminate,要等待 selection requests, `xclip .bashrc` 之后如果马上用鼠标选点什么东西,他就会马上返回结果。

http://stackoverflow.com/questions/19237559/why-xclip-bashrc-takes-much-longer-than-systemxclip-bashrc-in-ruby

需要 登录 后方可回复, 如果你还没有账号请 注册新账号