355

作为一个简单的例子,我想编写一个 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
4

10 回答 10

663
  • tput cols告诉你列数。
  • tput lines告诉你行数。
于 2008-11-04T23:40:49.717 回答
124

在 bash 中,环境变量$LINES$COLUMNS环境变量应该可以解决问题。将在终端大小发生任何变化时自动设置。(即SIGWINCH信号)

于 2009-02-19T01:30:49.907 回答
90

还有stty,见stty:打印或更改终端特性,更具体地说是特殊设置

$ stty size
60 120 # <= sample output

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

然后你可以使用或者cut提取awk你想要的部分。

这是stty size | cut -d" " -f1高度/线条和stty size | cut -d" " -f2宽度/列

于 2014-11-11T00:56:26.753 回答
21
yes = | head -n$(($(tput lines) * $COLUMNS)) | tr -d '\n'
于 2008-11-04T23:50:03.893 回答
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;
}

我希望它有用!

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

于 2011-09-27T20:08:51.243 回答
11

在 POSIX 上,最终您希望调用TIOCGWINSZ(Get WINdow SiZe)ioctl()调用。大多数语言应该有某种包装器。例如,在 Perl 中,您可以使用Term::Size

use Term::Size qw( chars );

my ( $columns, $rows ) = chars \*STDOUT;
于 2012-04-10T00:39:56.727 回答
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'];

不过要测试一下,因为我没有测试过。

于 2014-01-17T15:53:06.947 回答
3

受@pixelbeat 回答的启发,这里有一个水平条,由tput、轻微滥用printf填充/填充和tr

printf "%0$(tput cols)d" 0|tr '0' '='
于 2018-04-17T11:01:02.293 回答
1

获取窗口宽度

此 shell 代码使全局变量$TERM_SIZE跟踪终端窗口的大小:

set_term_size() {
    TERM_SIZE="$(stty size 2>/dev/null)" && [ "$TERM_SIZE" ] ||
        TERM_SIZE='25 80'
}
trap set_term_size WINCH
set_term_size

stty size它在回退到假设终端高 25 行,宽 80 个字符之前尝试过。POSIX 不要求` 的size操作数stty,因此需要回退。

然后,您可以使用 shell 的有限字符串替换功能访问 columsn 参数:

echo "${TERM_SIZE% *}" # Prints the terminal's height.
echo "${TERM_SIZE#* }" # Prints the terminal's width.

当然,您使用的脚本语言可能会提供一个库来为您处理这些问题——您应该使用它。

打印一行

一旦你知道终端的宽度,打印一条水平线就很容易了,例如,通过滥用printf的字符串填充:

printf '%*s\n' "${TERM_SIZE#* }" '' | 
tr ' ' -

第一行告诉管道printf打印与列一样多的空格(通过滥用字符串填充)。注意,POSIX没有提到*语法,所以这可能不像上面的代码那样可移植。

第二行告诉tr从该管道读取并用连字符替换每个空格。

于 2021-06-22T14:33:44.773 回答
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"
}
于 2019-01-02T15:14:40.727 回答