Redirecting stderr affects the output of "open FH, '- |', $ command". Why and how to prevent?
I want to get the size of the current terminal i.e. my perl script terminal works. The following should do the job:
#!/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";
Without the last but one line of code, it works as it should. But with this line I always get 24 x 80, so it seems like a new shell is internally created and the size of that shell is returned. This is just my guess. So what's really going on and how do I get both the STDERR redirect and the correct size?
source to share
To tput
determine the size of the terminal, one of the file descriptors for ( stdin ) stdout or stderr must be open and connected to the terminal.
In the construction, the pipe is stdout
connected to the pipe; if you redirect stderr
to a file then tput
returns the default size because it doesn't parse stdin
.
So it tput
doesn't have a terminal to work with; it returns the default size 24x80.
You can work around the problem by adding 2>/dev/tty
to the commands tput
:
open my $OH, '-|', "/usr/bin/tput lines 2>/dev/tty; /usr/bin/tput cols 2>/dev/tty"
or return @dimensions;
It seems that tput
does not look at stdin
. (Redirecting stdout
to a terminal will win over the mechanism Perl uses to read the information, of course.)
$ tput lines </dev/null
65
$ tput lines </dev/null 2>/dev/null
65
$ x=$(tput lines </dev/null 2>/dev/null)
$ echo $x
24
$
I added a diagnostic printout to the function to make sure it reads the output from tput
and it did. I added these lines to the function:
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;
and the output is:
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
When run on command line, the output is:
$ 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
$
So the standard input tput
remained the terminal, but tput
didn't look at it. So tput
had to look at stderr
(unclear if he tried it stdout
, but it was a channel) and not in stdin
. fstat
is a home-brew command, similar in spirit to stat
but with a different output format.
source to share