Чи існує спосіб у 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()
Якщо ви хочете, щоб рядки Unicode для сумісності з 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
РЕДАКТ : о, пробач. Це не стандартна пітонова версія, ось джерело 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, оскільки winize-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
л.с. та к.с. повинні містити ширину та висоту пікселів, але не слід.
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)
призведе до виходу з ладу, якщо ви покладете на stdin. Спробуйте: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 хвилин, перш ніж я помітив невідповідність.
Шрідхар, я не отримав цієї помилки, коли передавав трубопровід. Я майже впевнений, що його правильно потрапляють у випробування.
pascal, "HHHH"
не працює на моїй машині, але "hh"
робить. У мене виникли проблеми з пошуку документації для цієї функції. Схоже, це залежить від платформи.
chochem, включений.
Ось моя версія:
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
@ rean year відповідь працює добре, але проблема з цим: 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 terminize (): імпорт shlex, підпроцес, повторно output = subprocess.check_output (shlex.split ('/ bin / stty -a')) m = re.search ('рядки \ D + (? p \ d +); стовпці \ D + (? p \ d +);', вихід) якщо м: повернути m.group ('рядки'), m.group ('стовпці') підняти OSError ('Погана відповідь:% s'% (вихід))
>>> терміни () ('40', '100')