Pergunta

Existe uma maneira em python para determinar programaticamente a largura do console? Quero dizer o número de caracteres que se encaixa em uma linha sem acondicionamento, não a largura pixel da janela.

Editar

À procura de uma solução que funciona no Linux

Foi útil?

Solução

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

utiliza o comando 'tamanho stty', que de acordo com a um fio na lista de discussão python é razoavelmente universal no linux. Ele abre o comando 'tamanho stty' como um arquivo, 'lê' a partir dele, e usa uma fração de seqüência simples de separar as coordenadas.

Ao contrário do os.environ [ "colunas"] valor (que eu não posso acesso, apesar de usar o bash como meu shell padrão) os dados também serão up-to-date enquanto eu acredito que o os.environ [" COLUNAS "value] só seria válida para o momento do lançamento do interpretador Python (suponha que o usuário redimensionar a janela desde então).

Outras dicas

Não sei por que ele está no shutil módulo, mas ele pousou lá em Python 3.3, Consultando o tamanho da saída terminal:

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

Uma implementação de baixo nível está no módulo os.

Um backport está agora disponível para Python 3.2 e abaixo:

uso

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

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

Editar : oh, eu sinto muito. Isso não é um padrão python lib um, aqui está a fonte de console.py (Eu não sei de onde vem).

O módulo parece funcionar assim: ele verifica se termcap é acessível, quando sim. Ele usa isso; se não ele verifica se os suportes terminais um chamado especial ioctl e que não funciona, também, que verifica as variáveis ??de ambiente algumas conchas exportam para isso. Este, provavelmente, o trabalho em apenas 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])

código acima não retornou resultado correto no meu linux porque winsize-estrutura tem 4 calções não assinados, não 2 calções assinados:

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 e hp deve conter pixels de largura e altura, mas não.

Eu procurei ao redor e encontrei uma solução para janelas em:

http://code.activestate.com/recipes/ 440694-determinar-size-de-consola-window-on-windows /

e uma solução para Linux aqui.

Então aqui está uma versão que funciona tanto em Linux, OS X e 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

A partir de Python 3.3 é simples: https://docs.python.org/3/library/ os.html # consulta-the-tamanho-of-a-terminal

>>> import os
>>> ts = os.get_terminal_size()
>>> ts.lines
24
>>> ts.columns
80

É tanto:

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

A função shutil é apenas um invólucro em torno os um que pega alguns erros e criar um fallback, no entanto, tem um enorme ressalva! - quebra quando tubulação , que é um muito grande negócio.
Para ter obter o tamanho do terminal quando tubulação uso os.get_terminal_size(0) vez.

O primeiro argumento 0 é um argumento indicando que descritor de arquivo stdin deve ser usado em vez de stdout padrão. Queremos usar stdin porque stdout se desliga quando está a ser canalizado o que levanta neste caso desencadeia um erro ..
Eu tentei descobrir quando seria faz sentido usar stdout em vez de stdin argumento e não tenho idéia por que um padrão aqui.

Parece que existem alguns problemas com esse código, Johannes:

  • getTerminalSize precisa import os
  • o que é env? olhares como os.environ.

Além disso, por que mudar lines e cols antes de retornar? Se TIOCGWINSZ e stty tanto lines dizer então cols, eu digo deixá-lo assim. Isso me confundiu por um bom 10 minutos antes de eu notei a inconsistência.

Sridhar, eu não tive esse erro quando eu canalizada saída. Tenho certeza de que ele está sendo capturado corretamente no try-exceto.

pascal, "HHHH" não funciona na minha máquina, mas "hh" faz. Eu tinha documentação constatação de problemas para essa função. Parece que de plataforma dependente.

chochem, incorporada.

Aqui está a minha versão:

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)

Muitos dos Python 2 implementações aqui vai falhar se não houver controle de terminal quando você chamar este script. Você pode verificar sys.stdout.isatty () para determinar se este é de fato um terminal, mas que exclui um monte de casos, então eu acredito que a maneira mais Python para descobrir o tamanho do terminal é usar o builtin amaldiçoa pacote.

import curses
w = curses.initscr()
height, width = w.getmaxyx()

Eu estava tentando a solução a partir daqui que chama por stty size:

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

No entanto, este não para mim, porque eu estava trabalhando em um script que espera redirecionado entrada em stdin, e stty iria reclamar que "stdin não é um terminal" nesse caso.

Eu era capaz de fazê-lo funcionar como este:

with open('/dev/tty') as tty:
    height, width = subprocess.check_output(['stty', 'size'], stdin=tty).split()
resposta

@ do reannual funciona bem, mas há um problema com ele: os.popen agora está obsoleta . O módulo subprocess deve ser usado em vez disso, então aqui está uma versão do @ do reannual código que usa subprocess e directamente responde à pergunta (dando a largura da coluna diretamente como um int:

import subprocess

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

Testado em OS X 10.9

Tente "bênçãos"

Eu estava procurando a mesma coisa. É muito fácil de usar e oferece ferramentas para colorir, estilo e posicionamento no terminal. O que você precisa é tão fácil como:

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

Funciona como um encanto em Linux. (Não tenho certeza sobre MacOSX e Windows)

Faça o download e documentação aqui

ou você pode instalá-lo com pip:

pip install blessings

Se você estiver usando Python 3.3 ou acima, eu recomendo o built-in get_terminal_size() como já recomendado. No entanto, se você está preso com uma versão mais antiga e quer uma maneira simples, multi-plataforma de fazer isso, você pode usar asciimatics . Este pacote suporta versões do Python volta para 2.7 e usa opções semelhantes às sugeridas acima para obter o tamanho / console terminal atual.

Simplesmente construir sua classe Screen e use a propriedade dimensions para obter a altura e largura. Esta tem sido comprovada para trabalhar em Linux, OSX e Windows.

Oh - e divulgação completa aqui:. Eu sou o autor, então sinta-se livre para abrir um novo problema se você tiver quaisquer problemas em obter esta ao trabalho

Aqui está uma versão que deve ser Linux e Solaris compatível. Com base nos posts e commments de madchine . Requer o módulo subprocesso.

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')
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top