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

作为一个简单的例子,我想写一个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
214775 次浏览
  • tput cols告诉你列的数量。
  • tput lines告诉你行数。
yes = | head -n$(($(tput lines) * $COLUMNS)) | tr -d '\n'

在bash中,$LINES$COLUMNS环境变量应该能够做到这一点。将在终端大小发生任何变化时自动设置。(即SIGWINCH信号)

要在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;
}

希望对大家有用!

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

在POSIX上,最终你需要调用TIOCGWINSZ(获取窗口大小)ioctl()调用。大多数语言都应该为此提供某种包装器。在Perl中,你可以使用词:大小:

use Term::Size qw( chars );


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

正如我在lyceus answer中提到的,他的代码将在非英语区域设置的Windows上失败,因为mode的输出可能不包含子字符串“columns”或“lines”:

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, < img src = " https://i.stack.imgur.com/qwUgY.png " alt =”模式命令输出”>

你可以找到正确的子字符串而不寻找文本:

 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'];

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

还有stty,请参见stty:打印或更改终端特征,更确切地说是特殊的设置

$ stty size
60 120 # <= sample output


# To read into variables, in bash
$ read -r rows cols < <(stty size)
$ echo "rows: $rows, cols: $cols"
rows: 60, cols: 120

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

或者你可以使用cutawk来提取你想要的部分。

这是stty size | cut -d" " -f1用于高度/行,stty size | cut -d" " -f2用于宽度/列

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

printf "%0$(tput cols)d" 0|tr '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"
}

获取窗口宽度

这个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的强制使用stty '的size操作数,因此需要回退。

然后你可以使用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将有多少列的空格(通过滥用字符串paddin)打印到一个管道中。注意,POSIX没有提到*语法,所以这可能不像上面的代码那样可移植。

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