我想获取当前终端的大小,即我的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
,但这是一个管道),而不是stdin
。 fstat
是一种自酿啤酒的命令,其本质上与stat
相似,但是其输出格式不同。