Cómo obtener el ancho de la ventana de la consola Linux en Python


¿Hay alguna forma en python de determinar programáticamente el ancho de la consola? Me refiero al número de caracteres que cabe en una línea sin envolver, no al ancho de píxel de la ventana.

Editar

Buscando una solución que funcione en Linux

Author: anatoly techtonik, 2009-02-19

14 answers

import os
rows, columns = os.popen('stty size', 'r').read().split()

Utiliza el comando 'stty size' que según un hilo en la lista de correo de python es razonablemente universal en linux. Abre el comando 'stty size' como un archivo, 'lee' de él, y usa una simple división de cadena para separar las coordenadas.

A diferencia del sistema operativo.environ ["COLUMNS"] valor (al que no puedo acceder a pesar de usar bash como mi shell estándar) los datos también estarán actualizados, mientras que creo que el sistema operativo.environ ["COLUMNS"] value would only be valid for the time of el lanzamiento del intérprete de python (supongamos que el usuario redimensionó la ventana desde entonces).

 226
Author: brokkr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-03 10:06:54

No estoy seguro de por qué está en el módulo shutil, pero aterrizó allí en Python 3.3, Consultando el tamaño del terminal de salida :

>>> import shutil
>>> shutil.get_terminal_size((80, 20))  # pass fallback
os.terminal_size(columns=87, lines=23)  # returns a named-tuple

Una implementación de bajo nivel está en el módulo de so.

Un backport ahora está disponible para Python 3.2 y versiones posteriores:

 188
Author: Gringo Suave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-30 17:45:29

Use

import console
(width, height) = console.getTerminalSize()

print "Your terminal's width is: %d" % width

EDIT: oh, lo siento. Eso no es una lib estándar de python, aquí está la fuente de console.py (No se de donde es).

El módulo parece funcionar así: Comprueba si termcap está disponible, cuando sí. Usa eso; si no comprueba si el terminal soporta una llamada especial ioctl y eso no funciona, también comprueba las variables de entorno que algunos shells exportan para eso. Esto probablemente funcionará solo en UNIX.

def getTerminalSize():
    import os
    env = os.environ
    def ioctl_GWINSZ(fd):
        try:
            import fcntl, termios, struct, os
            cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
        '1234'))
        except:
            return
        return cr
    cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
    if not cr:
        try:
            fd = os.open(os.ctermid(), os.O_RDONLY)
            cr = ioctl_GWINSZ(fd)
            os.close(fd)
        except:
            pass
    if not cr:
        cr = (env.get('LINES', 25), env.get('COLUMNS', 80))

        ### Use get(key[, default]) instead of a try/catch
        #try:
        #    cr = (env['LINES'], env['COLUMNS'])
        #except:
        #    cr = (25, 80)
    return int(cr[1]), int(cr[0])
 65
Author: Johannes Weiss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-14 19:38:02

El código anterior no devolvió el resultado correcto en mi linux porque winsize-struct tiene 4 cortos sin firmar, no 2 cortos firmados:

def terminal_size():
    import fcntl, termios, struct
    h, w, hp, wp = struct.unpack('HHHH',
        fcntl.ioctl(0, termios.TIOCGWINSZ,
        struct.pack('HHHH', 0, 0, 0, 0)))
    return w, h

Hp y hp deben contener ancho y alto de píxeles, pero no lo hacen.

 49
Author: pascal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-09 22:36:38

Busqué alrededor y encontré una solución para windows en :

Http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/

Y una solución para linux aquí.

Así que aquí hay una versión que funciona tanto en linux, os x y windows / cygwin:

""" getTerminalSize()
 - get width and height of console
 - works on linux,os x,windows,cygwin(windows)
"""

__all__=['getTerminalSize']


def getTerminalSize():
   import platform
   current_os = platform.system()
   tuple_xy=None
   if current_os == 'Windows':
       tuple_xy = _getTerminalSize_windows()
       if tuple_xy is None:
          tuple_xy = _getTerminalSize_tput()
          # needed for window's python in cygwin's xterm!
   if current_os == 'Linux' or current_os == 'Darwin' or  current_os.startswith('CYGWIN'):
       tuple_xy = _getTerminalSize_linux()
   if tuple_xy is None:
       print "default"
       tuple_xy = (80, 25)      # default value
   return tuple_xy

def _getTerminalSize_windows():
    res=None
    try:
        from ctypes import windll, create_string_buffer

        # stdin handle is -10
        # stdout handle is -11
        # stderr handle is -12

        h = windll.kernel32.GetStdHandle(-12)
        csbi = create_string_buffer(22)
        res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
    except:
        return None
    if res:
        import struct
        (bufx, bufy, curx, cury, wattr,
         left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
        sizex = right - left + 1
        sizey = bottom - top + 1
        return sizex, sizey
    else:
        return None

def _getTerminalSize_tput():
    # get terminal width
    # src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
    try:
       import subprocess
       proc=subprocess.Popen(["tput", "cols"],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
       output=proc.communicate(input=None)
       cols=int(output[0])
       proc=subprocess.Popen(["tput", "lines"],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
       output=proc.communicate(input=None)
       rows=int(output[0])
       return (cols,rows)
    except:
       return None


def _getTerminalSize_linux():
    def ioctl_GWINSZ(fd):
        try:
            import fcntl, termios, struct, os
            cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,'1234'))
        except:
            return None
        return cr
    cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
    if not cr:
        try:
            fd = os.open(os.ctermid(), os.O_RDONLY)
            cr = ioctl_GWINSZ(fd)
            os.close(fd)
        except:
            pass
    if not cr:
        try:
            cr = (env['LINES'], env['COLUMNS'])
        except:
            return None
    return int(cr[1]), int(cr[0])

if __name__ == "__main__":
    sizex,sizey=getTerminalSize()
    print  'width =',sizex,'height =',sizey
 35
Author: Harco Kuppens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-05 09:22:23

A partir de Python 3.3 es sencillo: https://docs.python.org/3/library/os.html#querying-the-size-of-a-terminal

>>> import os
>>> ts = os.get_terminal_size()
>>> ts.lines
24
>>> ts.columns
80
 15
Author: Bob Enohp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-27 23:24:31

Parece que hay algunos problemas con ese código, Johannes: {[14]]}

  • getTerminalSize necesita import os
  • ¿qué es env? parece os.environ.

También, ¿por qué cambiar lines y cols antes de regresar? Si TIOCGWINSZ y stty ambos dicen lines entonces cols, yo digo que lo dejes así. Esto me confundió por un buen 10 minutos antes de que me di cuenta de la inconsistencia.

Sridhar, no obtuve ese error cuando canalé la salida. Estoy bastante seguro de que está siendo atrapado correctamente en el inténtalo, excepto.

Pascal, "HHHH" no funciona en mi máquina, pero "hh" hace. Tuve problemas para encontrar documentación para esa función. Parece que depende de la plataforma.

Chochem, incorporated.

Aquí está mi versión:

def getTerminalSize():
    """
    returns (lines:int, cols:int)
    """
    import os, struct
    def ioctl_GWINSZ(fd):
        import fcntl, termios
        return struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234"))
    # try stdin, stdout, stderr
    for fd in (0, 1, 2):
        try:
            return ioctl_GWINSZ(fd)
        except:
            pass
    # try os.ctermid()
    try:
        fd = os.open(os.ctermid(), os.O_RDONLY)
        try:
            return ioctl_GWINSZ(fd)
        finally:
            os.close(fd)
    except:
        pass
    # try `stty size`
    try:
        return tuple(int(x) for x in os.popen("stty size", "r").read().split())
    except:
        pass
    # try environment variables
    try:
        return tuple(int(os.getenv(var)) for var in ("LINES", "COLUMNS"))
    except:
        pass
    # i give up. return default.
    return (25, 80)
 6
Author: thejoshwolfe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-16 07:23:51

Muchas de las implementaciones de Python 2 aquí fallarán si no hay un terminal de control cuando llame a este script. Puede comprobar sys.stdout.isatty () para determinar si esto es de hecho una terminal, pero eso excluirá un montón de casos, así que creo que la forma más pitónica de averiguar el tamaño de la terminal es usar el paquete integrado curses.

import curses
w = curses.initscr()
height, width = w.getmaxyx()
 6
Author: wonton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-31 22:26:04

Es:

import os
columns, rows = os.get_terminal_size(0)
# or
import shutil
columns, rows = shutil.get_terminal_size()

La función shutil es solo una envoltura alrededor de os que detecta algunos errores y configura una reserva, sin embargo, tiene una gran advertencia: ¡se rompe al canalizar!, lo cual es bastante importante.
Para obtener el tamaño del terminal cuando se utiliza la tubería os.get_terminal_size(0) en su lugar.

Primer argumento 0 es un argumento que indica que el descriptor de archivo stdin debe ser utilizado en lugar de la salida estándar predeterminada. Queremos usar stdin porque stdout se separa cuando está siendo canalizado que plantea en este caso plantea un error..
He intentado averiguar cuándo tendría sentido usar stdout en lugar del argumento stdin y no tengo idea de por qué es un valor predeterminado aquí.

 5
Author: Granitosaurus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-03 04:51:39

La respuesta de@reannual funciona bien, pero hay un problema con ella: os.popen ahora está en desuso . El módulo subprocess debe usarse en su lugar, por lo que aquí hay una versión del código de @reannual que usa subprocess y responde directamente a la pregunta (dando el ancho de la columna directamente como int:

import subprocess

columns = int(subprocess.check_output(['stty', 'size']).split()[1])

Probado en OS X 10.9

 1
Author: rickcnagy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-22 18:30:16

Estaba intentando la solución desde aquí que llama a stty size:

columns = int(subprocess.check_output(['stty', 'size']).split()[1])

Sin embargo, esto falló para mí porque estaba trabajando en un script que espera la entrada redirigida en stdin, y stty se quejaría de que "stdin no es una terminal" en ese caso.

Pude hacer que funcionara así:

with open('/dev/tty') as tty:
    height, width = subprocess.check_output(['stty', 'size'], stdin=tty).split()
 1
Author: Marc Liyanage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-08 18:36:32

Intenta "bendiciones"

Estaba buscando lo mismo. Es muy fácil de usar y ofrece herramientas para colorear, estilo y posicionamiento en el terminal. Lo que necesitas es tan fácil como:

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

Funciona como un encanto en Linux. (No estoy seguro sobre MacOSX y Windows)

Descarga y documentación aquí

O puede instalarlo con pip:

pip install blessings
 1
Author: Iman Akbari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-23 12:00:41

Si está utilizando Python 3.3 o superior, le recomendaría el incorporado get_terminal_size() como ya se recomienda. Sin embargo, si está atascado con una versión anterior y desea una forma simple y multiplataforma de hacer esto, podría usar asciimatics. Este paquete soporta versiones de Python de vuelta a la 2.7 y usa opciones similares a las sugeridas anteriormente para obtener el tamaño actual de terminal / consola.

Simplemente construya su clase Screen y use la propiedad dimensions para obtener la altura y el ancho. Esto tiene se ha demostrado que funciona en Linux, OSX y Windows.

Oh - y la divulgación completa aquí: Yo soy el autor, así que por favor no dude en abrir un nuevo número si tiene algún problema para conseguir que esto funcione.

 1
Author: Peter Brittain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-24 09:54:50

Aquí hay una versión que debería ser compatible con Linux y Solaris. Basado en los mensajes y comentarios de madchine . Requiere el módulo subprocess.

def termsize():
    import shlex, subprocess, re
    output = subprocess.check_output(shlex.split('/bin/stty -a'))
    m = re.search('rows\D+(?P\d+); columns\D+(?P\d+);', output)
    if m:
        return m.group('rows'), m.group('columns')
    raise OSError('Bad response: %s' % (output))
>>> termsize()
('40', '100')
 0
Author: Derrick Petzold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:19