如何找到终端窗口的宽度和高度?


295

作为一个简单的示例,我想编写一个CLI脚本,该脚本可以=在终端窗口的整个宽度上打印。

#!/usr/bin/env php
<?php
echo str_repeat('=', ???);

要么

#!/usr/bin/env python
print '=' * ???

要么

#!/usr/bin/env bash
x=0
while [ $x -lt ??? ]; do echo -n '='; let x=$x+1 done; echo

我创建了这个小巧的node.js库,以便始终获得正确的窗口大小npmjs.com/package/window-size
jonschlinkert

Answers:


562
  • tput cols 告诉您列数。
  • tput lines 告诉您行数。

11
echo -e "lines\ncols"|tput -S要获取行和列,请参阅:linux.about.com/library/cmd/blcmdl1_tput.htm
nickl

4
tput是一个很棒的命令,其中包含许多用于读取终端状态,控制光标和文本属性等的命令。
Drew Noakes 2014年

2
方便的别名,例如:alias dim="echo $(tput cols)x$(tput lines)",可能会导致80x50
主教

2
该问答可能属于unix或超级用户SE网站。
mydoghasworms

2
当外壳程序被获取时,@ bishop您提供的alias命令将得到评估。您需要对alias命令使用单引号。像这样: alias dim='echo Terminal Dimensions: $(tput cols) columns x $(tput lines) rows'
brandonsimpkins

103

在bash中,$LINES$COLUMNS环境变量应该可以解决问题。端子尺寸的任何更改都会自动设置。(即SIGWINCH信号)


18
但是,这些环境变量仅适用于bash,不适用于在bash中运行的任何程序(如perl,python,ruby)。
Br.Bill

9
除交互式bash会话外,该方法不起作用(如果您运行脚本,它将不再是交互式的)。在脚本中唯一可以使用它的地方是bash中的hint_command。
Doncho Gunchev 2014年

1
实际上,如果您设置了该checkwinsize选项,它确实可以在非交互式脚本中工作。例如,此非交互式脚本将打印运行该脚本的终端的尺寸:(shopt -s checkwinsize; (:); echo $LINES $COLUMNScheckwinsize选项仅在等待子shell完成后才初始化变量,这就是我们需要该(:)语句的原因)
user3340662

$LINES$COLUMNSSIGWINCH发送后(实际上是在执行任何交互式命令之后)进行更新。如果您尝试更新PS1trap SIGWINCH您不能使用$LINES$COLUMNS他们保持旧值((
gavenkoa

LINES并且COLUMNS仅由bash 设置为shell变量。Bash不会将它们设置为环境变量,除非您导出这些shell变量。
Markus Kuhn

67

还有stty,来自coreutils

$ stty size
60 120 # <= sample output

它将分别打印行数和列数或高度和宽度。

然后,您可以使用cutawk提取所需的部分。

那是stty size | cut -d" " -f1为了高度/线条和stty size | cut -d" " -f2宽度/栏


此样式不能与PIPE一起使用,建议使用tput样式。
liuyang15年

6
tput的问题在于,尽管每个tty中的stty都可用,但它并不总是可用。感谢您提供的信息!
iRaS

16
yes = | head -n$(($(tput lines) * $COLUMNS)) | tr -d '\n'

3
不是直接回答问题,而是出色的演示脚本。
克里斯·佩奇

多么棒的例子!
Kurt Zhong

1
tr这些年来,我怎么想念命令?(facepalm)
Marco Massenzio

这是什么语言?它看起来像是带有语法错误的shell脚本。(在shell中,您不能在赋值等号周围有空格,并且第一条管道似乎
不合适

2
yes '='将输出无限数量的“ =”行,并且以下命令的组织足以填充终端
pixelbeat

12

为此,在Windows CLI环境中,我能找到的最好方法是使用mode命令并解析输出。

function getTerminalSizeOnWindows() {
  $output = array();
  $size = array('width'=>0,'height'=>0);
  exec('mode',$output);
  foreach($output as $line) {
    $matches = array();
    $w = preg_match('/^\s*columns\:?\s*(\d+)\s*$/i',$line,$matches);
    if($w) {
      $size['width'] = intval($matches[1]);
    } else {
      $h = preg_match('/^\s*lines\:?\s*(\d+)\s*$/i',$line,$matches);
      if($h) {
        $size['height'] = intval($matches[1]);
      }
    }
    if($size['width'] AND $size['height']) {
      break;
    }
  }
  return $size;
}

我希望它有用!

注意:返回的高度是缓冲区中的行数,而不是窗口中可见的行数。还有更好的选择吗?


3
请注意一个问题:此命令的输出是特定于语言环境的。换句话说,这将无法在其他Windows语言环境中正常工作。这就是我在Windows 7上获得的信息:i.imgur.com/Wrr7sWY.png
Camilo Martin

添加了解决方案的答案。+1!
卡米洛·马丁

10

最终,在POSIX上,您想调用TIOCGWINSZ(Get WINdow SiZe)ioctl()调用。大多数语言都应该为此提供某种包装。例如在Perl中,您可以使用Term :: Size

use Term::Size qw( chars );

my ( $columns, $rows ) = chars \*STDOUT;

1
谢谢您-引导我朝着正确的方向前进。Elixir::io.columnsErlang:io:columns(). erlang.org/doc/man/io.html#columns-0
Henrik N

2
TIOCGWINSZPOSIX标准中没有,ioctl()仅针对过时的STREAMS功能进行了定义。
osvein

4

正如我在lyceus答案中提到的那样,他的代码在非英语语言环境的Windows上将失败,因为那么输出mode可能不包含子字符串“ columns”或“ lines”:

                                         模式命令输出

您可以找到正确的子字符串而无需查找文本:

 preg_match('/---+(\n[^|]+?){2}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

请注意,我什至不打扰线条,因为它不可靠(而且我实际上并不在乎它们)。

编辑:根据有关Windows 8的评论(哦...),我认为这可能更可靠:

 preg_match('/CON.*:(\n[^|]+?){3}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

不过请进行测试,因为我没有进行测试。


您的方法在Win8中不起作用。我得到多---条线。i.imgur.com/4x02dqT.png
mpen 2014年

@Mark好,太好了,那只是美丽。谢谢Windows。<3(更相关的注释:Windows 9发行时,我将研究如何解决此问题:P)。
卡米洛·马丁

这是我做的方式:$mode = `mode`; list($rows, $cols) = array_slice(preg_split('/\n/', substr($mode, strpos($mode, 'CON:'))), 2, 2);。然后我只替换数字以外的所有内容。
Aleksandr Makov 2014年

@AleksandrMakov我想知道如果语言顺序相同CON device status:怎么办?也许匹配类似的东西CON.*:会更好。
卡米洛·马丁

1
@Mark我实际上是在问自己那件事。我为什么要这么做呢?毫无疑问,我只是认为有某种原因,然后就去了,哈哈。
卡米洛·马丁

1

受到@pixelbeat答案的启发,这是一个水平条,它是由tput,误用printf填充/填充和tr

printf "%0$(tput cols)d" 0|tr '0' '='

0

在某些情况下,您的行/行和列与所使用的“终端”的实际大小不匹配。也许您可能没有“ tput”或“ stty”可用。

这是一个bash函数,可用于直观地检查大小。最多可处理140列x 80行。您可以根据需要调整最大值。

function term_size
{
    local i=0 digits='' tens_fmt='' tens_args=()
    for i in {80..8}
    do
        echo $i $(( i - 2 ))
    done
    echo "If columns below wrap, LINES is first number in highest line above,"
    echo "If truncated, LINES is second number."
    for i in {1..14}
    do
        digits="${digits}1234567890"
        tens_fmt="${tens_fmt}%10d"
        tens_args=("${tens_args[@]}" $i)
    done
    printf "$tens_fmt\n" "${tens_args[@]}"
    echo "$digits"
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.