14

I want to output a progress bar, but how do I retrieve the terminal width in Perl?

A core Perl solution would be preferred, since I don't have access to a compiler, just an already installed 5.8.2 Perl.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Steve Schnepp
  • 4,620
  • 5
  • 39
  • 54
  • 5
    You always have access to a compiler. There's no law that says you have to compile it on the same host. – brian d foy Nov 23 '09 at 12:19
  • [sarcastic] Normally yes... but not here. Since everyone knows that Java & Perl can just be developed on any box, no need to have the same environment (read architecture) on the dev platform than the production one... [/sarcastic] – Steve Schnepp Nov 23 '09 at 15:14
  • 1
    Why the sarcasm? I'm giving you a serious answer. Your development and production systems don't really matter. You can cross-compile to either of them. You're here to get help and I gave you free help, so don't shit on it. – brian d foy Nov 23 '09 at 16:30
  • @brian: I'm sorry about it since I didn't want to be sarcastic on you, but more on ppl here that don't give me access to a compiler that targets the production architecture (hey, I knew you were serious, I even +1'd). – Steve Schnepp Nov 23 '09 at 17:21

4 Answers4

33

The FAQ which ships with Perl has the answer to this question. If you run perldoc -q "screen size", you'll get the following:

How do I get the screen size?

If you have Term::ReadKey module installed from CPAN, you can use it to fetch the width and height in characters and in pixels:

use Term::ReadKey;
($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize();

This is more portable than the raw "ioctl", but not as illustrative:

require 'sys/ioctl.ph';
die "no TIOCGWINSZ" unless defined &TIOCGWINSZ;
open(TTY, "+</dev/tty") or die "No tty: $!";
unless (ioctl(TTY, &TIOCGWINSZ, $winsize='')) {
    die sprintf "$0: ioctl TIOCGWINSZ (%08x: $!)\n", &TIOCGWINSZ;
}
($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
print "(row,col) = ($row,$col)";
print "  (xpixel,ypixel) = ($xpixel,$ypixel)" if $xpixel || $ypixel;
print "\n";

So you can use the last one if you want a pure Perl solution, or install Term::ReadKey from CPAN if you want a simpler solution in your code but more up-front set-up.

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
Matt Ryall
  • 9,977
  • 5
  • 24
  • 20
  • How do we run `h2ph` as implied by the error message : `Can't locate sys/ioctl.ph in @INC (did you run h2ph?)` – Steve Schnepp Nov 23 '09 at 10:11
  • @Steve: so what happens when you try to run `h2ph`? – Ether Nov 23 '09 at 18:12
  • @Ether: i missed the `-d` option of `h2ph`. Now it says `ioctl.pl: ioctl TIOCGWINSZ (40007468: A system call received a parameter that is not valid.)` – Steve Schnepp Dec 08 '09 at 16:40
  • I'd like to note that the TIOCGWINSZ did **not** work on BSD, but "many" people are already copying this "solution" because it does not seem to require additional modules. Please avoid it. – Nei Aug 07 '14 at 13:35
  • This won't work in a makefile. Apparently it's a bug to use this module in anything that doesn't have a controlling terminal, and of course it's make that's controlling the terminal. Too bad - I wonder if there's another way to get it working. (edit: probably making the makefile export COLUMNS and LINES will work, but it would be good if it tried tput or stty size). – rjh Aug 09 '16 at 17:29
14

This obviously depends on the platform, but a very simple solution that works out of the box on Linux is this:

my $width = `tput cols`;
roryrjb
  • 789
  • 9
  • 11
8

If you want to make a progress bar, don't sweat the details. Use one of the many progress bar modules on CPAN and be done with it.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • +1 for an *higher-level* answer. Too bad the Term::ProgressBar needs also Term::ReadKey :-( – Steve Schnepp Nov 23 '09 at 16:12
  • 1
    Console::ProgressBar is extremely basic, but IMO it does so better than Term::ProgressBar. In my comparison, ETA in the latter was the only reason I would prefer it (and only if your ticks are fairly uniform in runtime). – UncleCarl Jun 09 '23 at 17:29
6

Term::Size::Any looks to be what you're after.

Dan
  • 61,568
  • 9
  • 61
  • 78