3
irb(main):001:0> require 'benchmark'
=> true
irb(main):002:0> puts Benchmark.measure { system "xclip .bashrc" }
  0.000000   0.000000   0.000000 (  0.008030)
=> nil
irb(main):003:0> puts Benchmark.measure { `xclip .bashrc` }
  0.000000   0.000000   0.000000 ( 33.215158)
=> nil
irb(main):004:0> RUBY_VERSION
=> "2.0.0"

我已经阅读了互联网上关于从 ruby​​ 脚本调用 shell 命令的各种方法的几乎所有内容,但我就是不明白为什么Kernel#`需要比Kernel#system.

更新

Kernel#`只有xclip. 所有其他命令几乎都需要相同的时间。

4

2 回答 2

3

我怀疑xclip当你使用反引号来结束时,它只需要很长时间才能终止。这与选择有关。如果没有通过它提供任何选择-sel,它将默认XA_PRIMARY使用通常用于通过鼠标中键实现复制和粘贴的选项。

当你跑

$ xclip text.txt

内容变为可用,XA_PRIMARY这意味着您可以通过鼠标中键或$ xclip -o. 当你通过 Ruby 中的 shell 执行它时,它开始变得很奇怪:

ruby -e '`xclip text.txt`

如果你什么都不做,它永远不会真正终止。当您在 X11 系统中选择某些东西时,它会终止,例如在控制台或其他任何地方。只是选择,用鼠标标记一些东西。如果你不这样做,它会在某个时候挂起和/或超时。

当您使用详细模式时,可以观察到相同的行为:

$ xclip -verbose text.txt

Connected to X server.
Using UTF8_STRING.
Reading text.txt...
Waiting for selection requests, Control-C to quit
  Waiting for selection request number 1

当您选择某些内容时,再次提供选择请求。

一个很好的分析工具是strace(该-f选项也用于跟踪分叉)

$ strace -f ruby -e '`xclip text.txt`'

...
poll([{fd=3, events=POLLIN|POLLOUT}], 1, 4294967295) = 1 ([{fd=3, revents=POLLOUT}])
writev(3, [{"\20\0\3\0\4\0\200\2INCR", 12}, {NULL, 0}, {"", 0}], 3) = 12
poll([{fd=3, events=POLLIN}], 1, 4294967295) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "\1\0\f\0\0\0\0\0\235\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096,                                                                      0, NULL, NULL) = 32
recvfrom(3, 0x165e964, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(3, 0x165e964, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=3, events=POLLIN}], 1, 4294967295

在最后一行,它挂起,直到做出选择。poll()用于在文件描述符处等待文件事件。它会在某个时候终止,但 4,294,967,295 毫秒相当长。可以使用 just 进行相同的跟踪strace -f xclip text.txt

您可以通过查看文件描述符ls -l /proc/PID/fd。编号为 3 的文件描述符是xclip等待您选择的文件描述符。

使调试变得如此困难的原因是 if 立即终止strace xclip text.txt,而不是strace -f text.txt. 你想追踪分叉的那一刻它不再起作用了。这与您在使用 Ruby 时遇到的问题相同。它试图跟踪输出,因为Kernel#`想要返回输出。这可能也与票#9 ​​在从 stdin 设置剪贴板时不关闭标准输出有关。

这是我的理论。当您掏出并想要跟踪 的输出时xclip,无论是使用 Ruby 从标准输出读取,还是strace跟踪分叉,标准输出在您做出选择之前不会关闭。

这并不能很好地解释它,但它表明它不必与 Ruby 做任何事情。我将创建一个xclip仅关注而不是在 Ruby 上下文中的问题。

于 2013-10-08T16:54:22.730 回答
-1

您需要提供更多关于您使用 xclip 执行的操作的详细信息。B/c(因为)我的 ruby​​ 1.9.3 使用“echo hello”显示出最小的差异。

$ irb
irb(main):001:0> require 'benchmark'
=> true
irb(main):002:0> puts Benchmark.measure {  `echo hello` }
  0.000000   0.000000   0.000000 (  0.001471)
=> nil
irb(main):003:0> puts Benchmark.measure { system "echo hello" }
hello
  0.000000   0.000000   0.000000 (  0.001598)
=> nil
irb(main):004:0> RUBY_VERSION
=> "1.9.3"
于 2013-10-08T01:41:05.270 回答