too much php
too much php

Reputation: 90988

How do I find the width & height of a terminal window?

As a simple example, I want to write a CLI script which can print = across the entire width of the terminal window.

#!/usr/bin/env php
<?php
echo str_repeat('=', ???);

or

#!/usr/bin/env python
print '=' * ???

or

#!/usr/bin/env bash
x=0
while [ $x -lt ??? ]; do echo -n '='; let x=$x+1 done; echo

Upvotes: 434

Views: 265991

Answers (10)

Odin Kroeger
Odin Kroeger

Reputation: 41

Getting the window width

Make a global variable $termsize track the size of the terminal window:

settermsize() {
    termsize="$(stty size 2>/dev/null)" && [ "$termsize" ] ||
        termsize='25 80'
}
trap settermsize WINCH
settermsize

If stty size fails, the above code assumes that the terminals 80 columns wide and 25 lines high. POSIX does not mandate the size operand for stty, so the fallback is needed.

You can then access the columns argument by using the shell's string substitution capabilities:

echo "${termsize% *}" # Prints the terminal's height.
echo "${termsize#* }" # Prints the terminal's width.

Of course, the scripting language you use likely offers a library that takes care of that for you -- and you should use it.

Printing a line

Once you know the width of the terminal, printing a horizontal line is easy, for example, by abusing printf's string padding:

printf '%*s\n' "${termsize#* }" '' | 
tr ' ' -

The first line tells printf to print as many spaces as there are columns (by abusing string padding) to a pipe.

The second line tells tr to read from that pipe and replace every space with a hyphen.

Upvotes: 4

ryenus
ryenus

Reputation: 17381

And there's stty, see stty: Print or change terminal characteristics, more specifically Special settings

$ 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

It will print the number of rows and columns, or height and width, respectively.

Or you can use either cut or awk to extract the part you want.

That's stty size | cut -d" " -f1 for the height/lines and stty size | cut -d" " -f2 for the width/columns

Upvotes: 119

pourhaus
pourhaus

Reputation: 616

There are some cases where your rows/LINES and columns do not match the actual size of the "terminal" being used. Perhaps you may not have a "tput" or "stty" available.

Here is a bash function you can use to visually check the size. This will work up to 140 columns x 80 rows. You can adjust the maximums as needed.

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"
}

Upvotes: 1

huoneusto
huoneusto

Reputation: 1204

Inspired by @pixelbeat's answer, here's a horizontal bar brought to existence by tput, slight misuse of printf padding/filling and tr

printf "%0$(tput cols)d" 0|tr '0' '='

Upvotes: 5

Camilo Martin
Camilo Martin

Reputation: 37898

As I mentioned in lyceus answer, his code will fail on non-English locale Windows because then the output of mode may not contain the substrings "columns" or "lines":

                                         mode command output

You can find the correct substring without looking for text:

 preg_match('/---+(\n[^|]+?){2}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

Note that I'm not even bothering with lines because it's unreliable (and I actually don't care about them).

Edit: According to comments about Windows 8 (oh you...), I think this may be more reliable:

 preg_match('/CON.*:(\n[^|]+?){3}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

Do test it out though, because I didn't test it.

Upvotes: 4

TonyUser
TonyUser

Reputation: 8190

  • tput cols tells you the number of columns.
  • tput lines tells you the number of rows.

Upvotes: 788

LeoNerd
LeoNerd

Reputation: 8532

On POSIX, ultimately you want to be invoking the TIOCGWINSZ (Get WINdow SiZe) ioctl() call. Most languages ought to have some sort of wrapper for that. E.g in Perl you can use Term::Size:

use Term::Size qw( chars );

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

Upvotes: 11

lyceus
lyceus

Reputation: 149

To do this in Windows CLI environment, the best way I can find is to use the mode command and parse the output.

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

I hope it's useful!

NOTE: The height returned is the number of lines in the buffer, it is not the number of lines that are visible within the window. Any better options out there?

Upvotes: 12

David Dean
David Dean

Reputation: 7701

In bash, the $LINES and $COLUMNS environmental variables should be able to do the trick. The will be set automatically upon any change in the terminal size. (i.e. the SIGWINCH signal)

Upvotes: 145

pixelbeat
pixelbeat

Reputation: 31708

yes = | head -n$(($(tput lines) * $COLUMNS)) | tr -d '\n'

Upvotes: 24

Related Questions