我想获取当前终端的大小,即我的perl脚本在其中运行的终端。以下应完成此工作:

#!/usr/bin/perl

sub getTerminalSize {
    my @dimensions = (24,80);
    open( my $OH, '-|', "/usr/bin/tput lines ; /usr/bin/tput cols" )
        || return @dimensions;
    chomp(@dimensions = <$OH>);
    close($OH);
    return @dimensions;
}

open (STDERR, ">>bla.log") or die "can not create logfile";
print "Dimensions of your terminal: ". (join " x " , getTerminalSize()) ."\n";


没有最后一行,只有一行代码可以正常工作。
但是在这行代码中,我总是得到24 x 80,因此似乎在内部创建了一个新的shell,并返回了该shell的大小。只是我的猜测。
那么,实际上发生了什么,如何获得这两者-重定向STDERR和正确的大小?

最佳答案

为了使tput识别终端大小,必须打开(stdin,)stdout或stderr的文件描述符之一并将其连接到终端。

在管道结构中,stdout连接到管道。如果将stderr重定向到文件,则tput返回默认大小,因为它不分析stdin

因此,tput没有终端可以使用;它返回默认尺寸24x80。



您可以通过将2>/dev/tty添加到tput命令来解决此问题:

open my $OH, '-|', "/usr/bin/tput lines 2>/dev/tty; /usr/bin/tput cols 2>/dev/tty"
    or return @dimensions;


看来tput根本没有看stdin。 (当然,将stdout重定向到终端会破坏Perl用于读取信息的管道机制。)



$ tput lines </dev/null
65
$ tput lines </dev/null 2>/dev/null
65
$ x=$(tput lines </dev/null 2>/dev/null)
$ echo $x
24
$


我在该函数中添加了诊断打印,以确保它正在读取tput的输出,并且确实如此。我在功能中添加了以下几行:

open( my $OH, '-|', "fstat /dev/fd/0 /dev/fd/1 /dev/fd/2 /dev/null")
    or die "horribly";
my(@data) = <$OH>;
close($OH);
print @data;


输出为:

   Mode  Inode Links   UID   GID     Size    Modtime       Dev      RDev File
0020620    623     1   503     4        0 1333369875 334992488 268435457 /dev/fd/0
0010660 590945904     0   503    20        0 1333369875 334992488         0 /dev/fd/1
0100644 111429666     1   503    20        0 1333369875 334992488         0 /dev/fd/2
0020666    304     1     0     0        0 1333359963 334992488  50331650 /dev/null


在命令行上运行时,输出为:

$ fstat /dev/fd/[012] /dev/null
   Mode  Inode Links   UID   GID     Size    Modtime       Dev      RDev File
0020620    623     1   503     4        0 1333370018 334992488 268435457 /dev/fd/0
0020620    623     1   503     4        0 1333370018 334992488 268435457 /dev/fd/1
0020620    623     1   503     4        0 1333370018 334992488 268435457 /dev/fd/2
0020666    304     1     0     0        0 1333359963 334992488  50331650 /dev/null
$


因此,tput的标准输入仍然是终端,但是tput没有考虑。因此,tput必须查看了stderr(尚不清楚是否尝试了stdout,但这是一个管道),而不是stdinfstat是一种自酿啤酒的命令,其本质上与stat相似,但是其输出格式不同。

09-04 04:02