How can I “manually” get my terminal to return its (character) size?

Question:

Programs like resize ask the terminal about its size. And ultimately they will send some (ANSI) escape sequences to stdout and expect the terminal to react on those by itself returning some bytes.

The effect of the mechanism is visible with this interactive Python snippet:

>>> print('x1b[21;t')

Gnome-terminal will insert visibly something related to the window title on stdin.

Which script snippet will provoke the terminal to write it’s size (in characters)? If the size is returned invisible, some simple transformation should be done to see something. Shell, Python, Perl, whatever language is fine. As this will be terminal specific, any common terminal emulator is fine (e.g. xterm, gnome-terminal, terminator, …).

Clarification: I don’t care about programs which tell me the size. I know about TIOCGWINSZ, which does not work over serial lines. I want to see code which uses escape sequences, which actually works over serial lines.

Asked By: Robert Siemer

||

Answers:

I lifted this technique from the GNU source of stty(1) at http://code.metager.de/source/xref/gnu/coreutils/src/stty.c#1739. I tested it on OS X, and I could not guarantee it would work elsewhere, but its worth a try.

import fcntl
import termios
import struct

pad = "0" * 8
s = fcntl.ioctl(1, termios.TIOCGWINSZ, pad)
sz = struct.unpack('hhhh', s)
print("rows: {} columns: {}, xpixels: {}, ypixels: {}". format(*sz))

on my machine gives:

rows: 24 columns: 80, xpixels: 1200, ypixels: 600

Edit: The source code for os.get_terminal_size is in Modules/posixmodule.c with a function called get_terminal_size. One of the mechanisms is that shown above, but there are others depending on macros TERMSIZE_USE_IOCTL and TERMSIZE_USE_CONIO, the CONIO route is used for Windows.

Answered By: cdarke

The following program saves the current cursor position; moves the cursor to 999,999; queries the terminal for the current position; and restores the cursor position.

Assuming that your terminal is smaller than 999×999, this effectively queries the size of the terminal.

import sys
print('33[s33[999;999H33[6n33[u')
print(repr(next(sys.stdin)))

Resources:

Answered By: Robᵩ