如何在Ruby中获取终端窗口的宽度

51

您是否注意到,在Rails中运行rake -T时,rake描述列表会因终端窗口的宽度而被截断。因此,应该有一种方法在Ruby中获取并使用它。

我正在屏幕上打印一些ASCII艺术品,我不希望它被打破。因此,我需要找出终端的宽度,以便在运行时进行某种操作。

有任何想法如何实现吗?

9个回答

48

有一个常见的Unix命令:

tput cols

这会返回终端的宽度。


46

我发现在Ubuntu上,如果当Ruby应用程序正在运行时调整终端大小,则此处指定的其他方法(ENV['COLUMNS']tput columnshirb)都无法给出正确的结果。对于脚本而言这不是问题,但对于交互式控制台,如irb,则是一个问题。

ruby-terminfo gem是我目前找到的最好的解决方案,可以在调整终端大小后提供正确的尺寸,但需要您安装一个附加的gem,并且仅适用于Unix系统。

这个gem的使用非常简单:

require 'terminfo'
p TermInfo.screen_size        # [lines, columns]

TermInfo 内部使用 TIOCGWINSZ ioctl 获取屏幕大小。

另外,如 user83510 所提到的,highline 的 system_extensions 也可以使用:

require 'highline'
HighLine::SystemExtensions.terminal_size # [columns, lines]

在内部,highline在Unix上使用stty size,在ncurses和Windows上使用其他实现。

要监听终端大小的更改(而不是轮询),我们可以捕获SIGWINCH信号:

require 'terminfo'
Signal.trap('SIGWINCH', proc { puts TermInfo.screen_size.inspect })

对于使用Readline的应用程序,例如irb,这特别有用:

Signal.trap('SIGWINCH', proc { Readline.set_screen_size(TermInfo.screen_size[0], TermInfo.screen_size[1]) })

1
在底层,ruby-terminfo正在使用ioctl调用和4个无符号短结构体的TIOCGWINSZ。这些是列,行以及像素中的x,y。这里是直接链接的要点 https://gist.github.com/nixpulvis/6025433。 - Nathan Lilienthal
对于仍然访问此页面的任何人来说,另一个更轻巧的可以实现这个功能的宝石是https://github.com/rking/terminal-size。 - DannyB
1
在我的系统中,应该使用tput cols而不是tput columns - Mecki
我写了一个宝石来完成这个任务 https://github.com/piotrmurach/tty-screen - Piotr Murach
由于我已经安装了 highline,所以我想尝试那个解决方案...但是当我这样做时,我会得到:NameError(错误的颜色或未初始化的常量SystemExtensions)--是否需要安装其他附加的gem? 此外,正如已经提到的那样,它是tput cols而不是tput columns,在ubuntu下对我有用。 但是标准库的解决方案更好,因此我选择了在这里列出的io/console答案。 - lindes

37
def winsize
 #Ruby 1.9.3 added 'io/console' to the standard library.
 require 'io/console'
 IO.console.winsize
 rescue LoadError
 # This works with older Ruby, but only with systems
 # that have a tput(1) command, such as Unix clones.
[Integer(`tput li`), Integer(`tput co`)]
end

rows, cols = winsize
printf "%d rows by %d columns\n", rows, cols

链接


这个属于标准库的一部分,这是它的优点所在!Gems 当然很好,但对于如此简单的东西,不需要安装额外的内容也是一件很不错的事情。 - lindes

9

谢谢你给了我恰好想要的东西!顺便说一下,Gabriel,我正在我的Rails控制台中使用你的hirb gem,我非常喜欢它。谢谢啦。 - Allen Bargi

7
    require 'io/console'
    puts "Rows by columns: #{IO.console.winsize}"
    puts "Ruby 2.6.4"

4
这个回答被标记为低质量帖子并需要审核。以下是有关如何撰写高质量回答的一些指南:How do I write a good answer?。这个回答可能是正确的,但它需要一些解释来让人更好地理解。仅包含代码的回答不被认为是“好”的回答。来自审核 - MyNameIsCaleb
1
还有其他回答提供了OP的问题,并且它们是一段时间以前发布的。在发布答案时,请确保添加一个新的解决方案或者一个更加充分的解释,特别是在回答旧问题时。 - help-info.de
1
这是 Ruby 默认提供的简单功能。可惜它在底部。 - FluorescentGreen5
1
这里还有另一个问题。提供的评论被标记为低质量评论。这些提供的评论可能是正确的,但如果在评论之前阅读答案,则可以从中受益。机器人回复仅被认为是“好”的评论。还有其他提供相同剪贴板的评论,它们已经发布了数千次。在发表评论时,请确保您添加新的或实质性的评论,特别是在评论正确答案时。 - Nakilon

6

Ruby实际上自带了一个名为"Curses"的内置类,可以让你在终端窗口中做各种事情。

例如,您可以这样做:

require 'curses'

Curses.init_screen()

puts Curses.lines # Gives you the height of terminal window
puts Curses.cols # Gives you the width of terminal window

更多信息请参考:http://ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses/Window.html


这个链接提供了关于Curses/Window的Ruby文档。

5
更新:从 Ruby 2.1+ 开始,curses 不再是标准库的一部分。它现在已被移到自己的 gem 中。参见:https://bugs.ruby-lang.org/issues/8584 - Tom Lord

5

我有点晚了,但在rake任务中我会这样做:Rake.application.terminal_width

该代码片段用于获取当前终端的宽度。

非常好的答案,非常感谢!我需要它特别在一个 Rake 任务中。 - Konstantin Gredeskoul

3

ENV['COLUMNS']可以获取终端中的列数。


我在IRB中尝试了一下,并检查了ENV哈希表,但找不到columns键。 - Allen Bargi
这个技巧可能只适用于某些Shell或操作系统。在Debian的Bash下也无法工作。 - Wayne Conrad
在Ubuntu 11.04中对我起作用。我需要修改它,以便我的代码不会被截断,希望这有所帮助。(GNOME终端2.32.1) - Tass
在OSX和Solaris中,它只适用于bash,而不适用于在bash下运行的程序。如果您在bash中运行env,则看不到它,但是"echo $COLUMNS"有效。在这些平台上的ruby中,ENV ['COLUMNS']为nil。 - Br.Bill
在我的macOS 10.14上无法工作,没有设置这样的环境变量,即使使用Bash也不行。然而,在macOS上tput cols可以工作。 - Mecki

2
我编写了tty-screen gem,用于检测不同操作系统和Ruby解释器下的终端大小。它涵盖了许多检查大小的方法,包括Windows上的Win API、JRuby上的Java libs和Unix实用程序。
这是一个模块,您可以将其包含在您的类中或直接调用:
require 'tty-screen'

TTY::Screen.size     # => [51, 280]
TTY::Screen.width    # => 280
TTY::Screen.height   # => 51

更多信息请参见:https://github.com/piotrmurach/tty-screen


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接