Как получить ширину окна консоли Linux в Python



есть ли способ в python программно определить ширину консоли? Я имею в виду количество символов, которые помещаются в одну строку без обертывания, а не ширину пикселя окна.



Edit



ищу решение, которое работает на Linux

904   14  

14 ответов:

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

использует команду "stty size", которая в соответствии с нить в списке рассылки python достаточно универсален в linux. Он открывает команду "stty size" в виде файла, "читает" из него и использует простое разделение строк для разделения координат.

в отличие от операционной системы.значение environ ["столбцы"] (к которому я не могу получить доступ, несмотря на использование bash в качестве моей стандартной оболочки) данные также будут актуальными, тогда как я считаю, что ОС.environ ["столбцы"] значение будет только действительны на момент запуска интерпретатора Python (предположим, что пользователь изменил размер окна с тех пор).

не уверен, почему он находится в модуле shutil, но он приземлился там в Python 3.3, запрос размера выходного терминала:

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

реализация низкого уровня находится в модуле ОС.

теперь доступен backport для Python 3.2 и ниже:

использовать

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

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

EDIT: ой, простите. Это не стандартный lib python, вот источник console.py (я не знаю, откуда это).

модуль, кажется, работает так: он проверяет, если termcap есть в наличии, если да. Он использует это; если нет, он проверяет, поддерживает ли терминал специальный ioctl вызов и это тоже не работает, он проверяет переменные среды, которые некоторые оболочки экспортируют для этого. Это, вероятно, будет работать на 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])

код выше не вернул правильный результат на моем linux, потому что winsize-struct имеет 4 неподписанных шорты, а не 2 подписанных шорты:

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 и hp должны содержать ширину и высоту пикселя, но не делают.

Я искал вокруг и нашел решение для Windows по адресу :

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

и решение для Linux здесь.

Итак, вот версия, которая работает как на linux, os x и 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

начиная с Python 3.3 это прямо вперед: 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

похоже, что есть некоторые проблемы с этим кодом, Йоханнес:

  • getTerminalSize нужно import os
  • что это env? выглядит как os.environ.

кроме того, зачем переходить lines и cols перед возвращением? Если TIOCGWINSZ и stty как сказать lines затем cols, Я говорю оставить его таким образом. Это смутило меня в течение хороших 10 минут, прежде чем я заметил несоответствие.

Шридхар, я не получил эту ошибку, когда я трубил выход. Я почти уверен, что он был пойман правильно в попытке-за исключением.

Паскаль, "HHHH" не работает на моей машине, но "hh" делает. У меня были проблемы с поиском документации для этой функции. Похоже, что это зависит от платформы.

chochem, incorporated.

вот мой вариант:

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)

многие из реализаций Python 2 здесь потерпят неудачу, если при вызове этого скрипта не будет управляющего терминала. Вы можете проверить sys.стандартный вывод.isatty () чтобы определить, является ли это на самом деле терминалом, но это исключит кучу случаев, поэтому я считаю, что самый простой способ выяснить размер терминала-использовать встроенный пакет curses.

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

либо:

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

The .

первый аргумент 0 - это аргумент, указывающий на то, что вместо стандартного stdout следует использовать дескриптор файла stdin. Мы хотим использовать stdin, потому что stdout отсоединяется, когда он передается по конвейеру, который в этом случае вызывает ошибку..
Я попытался выяснить, когда имеет смысл использовать stdout вместо аргумента stdin и понятия не имею, почему он здесь по умолчанию.

@reannual ответ работает хорошо, но есть проблема с ним:os.popenтеперь не рекомендуется. Элемент , поэтому вот версия кода @reannual, которая использует subprocess и непосредственно отвечает на вопрос (давая ширину столбца непосредственно как int:

import subprocess

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

протестировано на OS X 10.9

Я пытался решить отсюда, что вызывает к stty size:

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

однако это не удалось для меня, потому что я работал над сценарием, который ожидает перенаправленного ввода на stdin, и stty будет жаловаться, что" stdin не является терминалом " в этом случае.

я смог заставить его работать так:

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

попробовать "благословения"

Я искал то же самое. Он очень прост в использовании и предлагает инструменты для окраски, укладки и позиционирования в терминале. То, что вам нужно, так же просто, как:

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

работает как шарм в Linux. (Я не уверен в MacOSX и Windows)

загрузка и документация здесь

или вы можете установить его с помощью pip:

pip install blessings

Если вы используете Python 3.3 или выше, я бы рекомендовал встроенный get_terminal_size() Как уже было рекомендовано. Однако если вы застряли с более старой версией и хотите простой, кросс-платформенный способ сделать это, вы можете использовать asciimatics. Этот пакет поддерживает версии Python до 2.7 и использует аналогичные параметры, предложенные выше, чтобы получить текущий размер терминала/консоли.

просто построить свой Screen классе и использовать dimensions свойство для получения высоты и ширина. Это было доказано, чтобы работать на Linux, OSX и Windows.

О-и полное раскрытие здесь: я автор, поэтому, пожалуйста, не стесняйтесь открывать новый выпуск, Если у вас есть какие-либо проблемы с получением этой работы.

вот версия, которая должна быть совместима с Linux и Solaris. На основе сообщений и сообщений от madchine. Требуется модуль подпроцесса.

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')

Comments

    Ничего не найдено.