Есть ли в Python способ программно определить ширину консоли? Я имею в виду количество символов, которые помещаются в одну строку без переноса, а не ширину окна в пикселях.
редактировать
Ищете решение, которое работает на Linux
Есть ли в Python способ программно определить ширину консоли? Я имею в виду количество символов, которые помещаются в одну строку без переноса, а не ширину окна в пикселях.
редактировать
Ищете решение, которое работает на Linux
Ответы:
import os
rows, columns = os.popen('stty size', 'r').read().split()
использует команду 'stty size', которая, согласно потоку в списке рассылки python, является достаточно универсальной в linux. Он открывает команду «stty size» в виде файла, «читает» из нее и использует простое разбиение строки для разделения координат.
В отличие от значения os.environ ["COLUMNS"] (к которому я не могу получить доступ, несмотря на использование bash в качестве стандартной оболочки), данные также будут современными, тогда как я считаю, что os.environ ["COLUMNS"] Значение будет действительным только для времени запуска интерпретатора Python (предположим, что пользователь изменил размер окна с тех пор).
(Смотрите ответ @GringoSuave о том, как это сделать на Python 3.3+)
rows, columns = subprocess.check_output(['stty', 'size']).split()
немного короче, плюс подпроцесс - будущее
rows, columns = subprocess.check_output(['stty', 'size']).decode().split()
Если вам нужны строки в кодировке Юникод для совместимости с py2 / 3
Не уверен, почему он находится в модуле 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
Низкоуровневая реализация находится в модуле os. Также работает в Windows.
Бэкпорт теперь доступен для Python 3.2 и ниже:
python3.5
.
Inappropriate ioctl for device
ошибках / предупреждениях, либо получал определенное запасное значение 80.
использование
import console
(width, height) = console.getTerminalSize()
print "Your terminal's width is: %d" % width
РЕДАКТИРОВАТЬ : о, я извиняюсь. Это не стандартная библиотека 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 должны содержать ширину и высоту пикселя, но не должны.
fcntl.ioctl(sys.stdin.fileno(), ...
stdout
или stderr
вместо stdin
, хотя. stdin
вполне может быть труба. Вы также можете добавить строку, например if not os.isatty(0): return float("inf")
.
Я искал вокруг и нашел решение для 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
Это либо:
import os
columns, rows = os.get_terminal_size(0)
# or
import shutil
columns, rows = shutil.get_terminal_size()
Эта shutil
функция является просто оберткой вокруг os
той, которая ловит некоторые ошибки и устанавливает запасной вариант, однако имеет одно огромное предостережение - она ломается при прокачке! Это довольно большое дело.
Чтобы получить размер терминала при использовании трубопровода, используйте os.get_terminal_size(0)
вместо этого.
Первый аргумент 0
- это аргумент, указывающий, что дескриптор файла stdin должен использоваться вместо стандартного stdout. Мы хотим использовать stdin, потому что stdout отключается, когда он передается по каналу, что в этом случае вызывает ошибку.
Я попытался выяснить, когда имеет смысл использовать stdout вместо аргумента stdin, и понятия не имею, почему это значение по умолчанию.
os.get_terminal_size()
был представлен в Python 3.3
os.get_terminal_size(0)
приведет к сбою, если вы отправите трубку на стандартный ввод Попробуйте:echo x | python3 -c 'import os; print(os.get_terminal_size(0))'
Начиная с 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
shutil.get_terminal_size() is the high-level function which should normally be used, os.get_terminal_size is the low-level implementation.
Похоже, с этим кодом есть некоторые проблемы, Йоханнес:
getTerminalSize
нуждается в import os
env
? выглядит как os.environ
.Также зачем переключаться lines
и cols
до возвращения? Если TIOCGWINSZ
и то , и stty
другое говорят lines
тогда cols
, я говорю, оставь это так. Это смутило меня на целых 10 минут, прежде чем я заметил несоответствие.
Шридхар, я не получил эту ошибку, когда передал вывод. Я почти уверен, что это правильно поймано в попытке.
Паскаль, "HHHH"
не работает на моей машине, но "hh"
работает. У меня были проблемы с поиском документации для этой функции. Похоже, это зависит от платформы.
Хохем, включены.
Вот моя версия:
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.stdout.isatty (), чтобы определить, является ли это на самом деле терминалом, но это исключит кучу случаев, поэтому я считаю, что самый питонный способ выяснить размер терминала - это использовать встроенный пакет curses.
import curses
w = curses.initscr()
height, width = w.getmaxyx()
Я пробовал решение отсюда, которое призывает 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
Ответ @ reannual работает хорошо, но есть проблема с ним: os.popen
теперь устарела . subprocess
Модуль должен использоваться вместо этого, так вот версия @ reannual код , который использует subprocess
и непосредственно отвечает на вопрос (давая ширину столбца непосредственно как int
:
import subprocess
columns = int(subprocess.check_output(['stty', 'size']).split()[1])
Протестировано на OS X 10.9
Если вы используете Python 3.3 или выше, я бы порекомендовал встроенный, get_terminal_size()
как уже рекомендовано. Однако, если вы застряли в более старой версии и хотите простой кроссплатформенный способ сделать это, вы можете использовать asciimatics . Этот пакет поддерживает версии Python до 2.7 и использует опции, аналогичные предложенным выше, чтобы получить текущий размер терминала / консоли.
Просто создайте свой Screen
класс и используйте dimensions
свойство, чтобы получить высоту и ширину. Доказано, что это работает на Linux, OSX и Windows.
О - и полное раскрытие здесь: я автор, поэтому, пожалуйста, не стесняйтесь открывать новый выпуск, если у вас есть какие-либо проблемы, чтобы заставить это работать.
Вот версия, которая должна быть совместима с Linux и Solaris. Основано на сообщениях и комментариях от Madchine . Требуется модуль подпроцесса.
def termize (): импорт шлекс, подпроцесс, ре output = subprocess.check_output (shlex.split ('/ bin / stty -a')) m = re.search ('строки \ D + (? P \ d +); столбцы \ D + (? P \ d +);', выходные данные) если М: вернуть m.group («строки»), m.group («столбцы») поднять OSError ('Неверный ответ:% s'% (вывод))
>>> termize () («40», «100»)