Как получить ширину окна консоли Linux в Python
есть ли способ в python программно определить ширину консоли? Я имею в виду количество символов, которые помещаются в одну строку без упаковки, а не ширину пикселя окна.
редактировать
поиск решения, которое работает на Linux
14 ответов
import os
rows, columns = os.popen('stty size', 'r').read().split()
использует команду "stty size", которая в соответствии с поток в списке рассылки python достаточно универсален в linux. Он открывает команду "stty size" в виде файла, "читает" из него и использует простое разделение строк для разделения координат.
в отличие от операционной системы.значение environ["COLUMNS"] (к которому я не могу получить доступ, несмотря на использование bash в качестве стандартной оболочки) данные также будут актуальными, тогда как я считаю, что ОС.значение environ ["COLUMNS"] будет только действителен на момент запуска интерпретатора 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
редактировать: о, извините. Это не стандартный 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 (), чтобы определить, действительно ли это терминал, но это исключит кучу случаев, поэтому я считаю, что самый питонический способ выяснить размер терминала-использовать встроенный пакет проклятий.
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()
на shutil
функция-это просто оболочка вокруг os
тот, который ловит некоторые ошибки и настраивает резерв, однако у него есть одно огромное предостережение -он ломается, когда трубопроводы!, что довольно большое дело.
Чтобы получить размер терминала при использовании трубопроводов .
первый аргумент 0
является аргументом, указывающим, что файловый дескриптор stdin должен использоваться вместо stdout по умолчанию. Мы хотим использовать stdin, потому что stdout отсоединяется, когда он передается по конвейеру, который в этом случае вызывает ошибку..
Я попытался выяснить, когда имеет смысл использовать stdout вместо аргумента stdin и понятия не имею, почему он здесь по умолчанию.
ответ@reannual работает хорошо, но с ним есть проблема:os.popen
в настоящее время осуждается. The , поэтому вот версия кода @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. На основе постов и commments от 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')