Czy w Pythonie jest sposób na programowe określenie szerokości konsoli? Mam na myśli liczbę znaków, która mieści się w jednej linii bez zawijania, a nie szerokość okna w pikselach.
Edytować
Szukasz rozwiązania, które działa w systemie Linux
Czy w Pythonie jest sposób na programowe określenie szerokości konsoli? Mam na myśli liczbę znaków, która mieści się w jednej linii bez zawijania, a nie szerokość okna w pikselach.
Edytować
Szukasz rozwiązania, które działa w systemie Linux
Odpowiedzi:
import os
rows, columns = os.popen('stty size', 'r').read().split()
używa komendy 'stty size', która zgodnie z wątkiem na liście mailingowej Pythona jest dość uniwersalna na Linuksie. Otwiera polecenie „rozmiar stty” jako plik, „odczytuje” z niego i wykorzystuje prosty podział łańcucha w celu oddzielenia współrzędnych.
W przeciwieństwie do wartości os.environ [„COLUMNS”] (do której nie mam dostępu pomimo używania bash jako mojej standardowej powłoki), dane również będą aktualne, podczas gdy uważam, że os.environ [„COLUMNS”] wartość będzie obowiązywać tylko w czasie uruchamiania interpretera python (załóżmy, że użytkownik zmienił rozmiar okna od tego czasu).
(Zobacz odpowiedź @GringoSuave na temat tego, jak to zrobić w Pythonie 3.3+)
rows, columns = subprocess.check_output(['stty', 'size']).split()
jest trochę krótszy, a podproces to przyszłość
rows, columns = subprocess.check_output(['stty', 'size']).decode().split()
Jeśli chcesz ciągów znaków Unicode dla kompatybilności py2 / 3
Nie jestem pewien, dlaczego znajduje się w module shutil
, ale wylądował tam w Pythonie 3.3, Sprawdzając rozmiar terminala wyjściowego :
>>> import shutil
>>> shutil.get_terminal_size((80, 20)) # pass fallback
os.terminal_size(columns=87, lines=23) # returns a named-tuple
Implementacja niskiego poziomu znajduje się w module OS. Działa również w systemie Windows.
Backport jest teraz dostępny dla Python 3.2 i poniżej:
python3.5
zainstalowany hosting współdzielony WebFaction .
Inappropriate ioctl for device
błędy / ostrzeżenia, albo otrzymałem zdefiniowaną wartość rezerwową 80.
posługiwać się
import console
(width, height) = console.getTerminalSize()
print "Your terminal's width is: %d" % width
EDYCJA : och, przepraszam. To nie jest standardowa wersja Pythona, oto źródło pliku console.py (nie wiem skąd).
Moduł wydaje się działać w ten sposób: sprawdza, czy termcap
jest dostępny, kiedy tak. Wykorzystuje to; jeśli nie, sprawdza, czy terminal obsługuje specjalne ioctl
wywołanie i to też nie działa, sprawdza zmienne środowiskowe, które eksportują niektóre powłoki. Prawdopodobnie będzie to działać tylko w systemie 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])
Powyższy kod nie zwrócił poprawnego wyniku na moim systemie Linux, ponieważ winsize-struct ma 4 spodenki bez podpisu, a nie 2 spodenki z podpisem:
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 i hp powinny zawierać szerokość i wysokość pikseli, ale nie.
fcntl.ioctl(sys.stdin.fileno(), ...
stdout
lub stderr
zamiast stdin
tego. stdin
może równie dobrze być fajką. Możesz także dodać linię taką jak if not os.isatty(0): return float("inf")
.
Rozejrzałem się i znalazłem rozwiązanie dla systemu Windows pod adresem:
http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/
i rozwiązanie dla systemu Linux tutaj.
Oto wersja, która działa zarówno na systemie Linux, OS X, jak i 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
To albo:
import os
columns, rows = os.get_terminal_size(0)
# or
import shutil
columns, rows = shutil.get_terminal_size()
Ta shutil
funkcja jest po prostu owijana wokół, os
która wychwytuje błędy i ustawia rezerwę, jednak ma jedno ogromne zastrzeżenie - psuje się podczas orurowania! , co jest dość dużą sprawą.
Aby uzyskać rozmiar terminala podczas instalacji rurowej, użyj os.get_terminal_size(0)
zamiast tego.
Pierwszy argument 0
to argument wskazujący, że zamiast domyślnego standardowego wyjścia należy użyć deskryptora pliku stdin. Chcemy użyć stdin, ponieważ stdout odłącza się podczas potoku, co w tym przypadku powoduje błąd.
Próbowałem dowiedzieć się, kiedy warto użyć argumentu stdout zamiast argumentu stdin i nie mam pojęcia, dlaczego jest to ustawienie domyślne.
os.get_terminal_size()
został wprowadzony w Pythonie 3.3
os.get_terminal_size(0)
spowoduje awarię, jeśli potokujesz do standardowego wejścia. Spróbuj:echo x | python3 -c 'import os; print(os.get_terminal_size(0))'
Począwszy od Python 3.3 jest to proste: 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.
Wygląda na to, że istnieją pewne problemy z tym kodem, Johannes:
getTerminalSize
musi import os
env
? wygląda os.environ
.Ponadto, po co przełączać lines
i cols
przed powrotem? Jeśli TIOCGWINSZ
i stty
obaj powiedzą lines
to cols
, mówię, zostaw to w ten sposób. Zdezorientowało mnie to przez dobre 10 minut, zanim zauważyłem niekonsekwencję.
Sridhar, nie dostałem tego błędu, gdy przesyłałem dane wyjściowe. Jestem prawie pewien, że został złapany prawidłowo w try-wyjątkiem.
pascal, "HHHH"
nie działa na moim komputerze, ale "hh"
działa. Miałem problem ze znalezieniem dokumentacji dla tej funkcji. Wygląda na to, że zależy od platformy.
chochem, włączony.
Oto moja wersja:
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)
Wiele implementacji języka Python 2 tutaj zawiedzie, jeśli podczas wywoływania tego skryptu nie będzie terminalu sterującego. Możesz sprawdzić sys.stdout.isatty (), aby ustalić, czy w rzeczywistości jest to terminal, ale to wykluczy kilka przypadków, więc uważam, że najbardziej pythonicznym sposobem ustalenia rozmiaru terminalu jest użycie wbudowanego pakietu curses.
import curses
w = curses.initscr()
height, width = w.getmaxyx()
Próbowałem stąd rozwiązania, które wzywa do stty size
:
columns = int(subprocess.check_output(['stty', 'size']).split()[1])
Jednak dla mnie to nie powiodło się, ponieważ pracowałem nad skryptem, który oczekuje przekierowanego wejścia na standardowe wejście, i stty
narzekałby, że „stdin nie jest terminalem” w tym przypadku.
Byłem w stanie sprawić, aby działało w następujący sposób:
with open('/dev/tty') as tty:
height, width = subprocess.check_output(['stty', 'size'], stdin=tty).split()
Spróbuj „błogosławieństw”
Szukałem tego samego. Jest bardzo łatwy w użyciu i oferuje narzędzia do kolorowania, stylizacji i pozycjonowania w terminalu. To, czego potrzebujesz, jest tak proste, jak:
from blessings import Terminal
t = Terminal()
w = t.width
h = t.height
Działa jak urok w Linuksie. (Nie jestem pewien co do MacOSX i Windows)
Pobierz i dokumentację tutaj
lub możesz zainstalować za pomocą pipa:
pip install blessings
Odpowiedź @ reannual działa dobrze, ale jest z tym problem: os.popen
jest teraz przestarzała . subprocess
Moduł powinien być stosowany zamiast, więc oto wersja użytkownika @ reannual kod, który używa subprocess
i jest bezpośrednio odpowiada na pytanie (podając szerokość kolumny bezpośrednio jako int
:
import subprocess
columns = int(subprocess.check_output(['stty', 'size']).split()[1])
Testowane na OS X 10.9
Jeśli używasz Pythona w wersji 3.3 lub nowszej, polecam wbudowaną wersję, get_terminal_size()
jak już zalecono. Jeśli jednak utkniesz w starszej wersji i chcesz prostego, wieloplatformowego sposobu na zrobienie tego, możesz użyć asciimatics . Ten pakiet obsługuje wersje Pythona z powrotem do wersji 2.7 i korzysta z opcji podobnych do tych sugerowanych powyżej, aby uzyskać bieżący rozmiar terminala / konsoli.
Wystarczy zbudować Screen
klasę i użyć dimensions
właściwości, aby uzyskać wysokość i szerokość. Udowodniono, że działa to w systemach Linux, OSX i Windows.
Aha - i pełne ujawnienie tutaj: jestem autorem, więc nie krępuj się otworzyć nowy problem, jeśli masz jakiekolwiek problemy z jego uruchomieniem.
Oto wersja, która powinna być kompatybilna z Linux i Solaris. Na podstawie postów i zamówień z madchine . Wymaga modułu podprocesu.
def Termsize (): importuj shlex, podproces, re output = subprocess.check_output (shlex.split ('/ bin / stty -a')) m = re.search ('wiersze \ D + (? P \ d +); kolumny \ D + (? P \ d +);', wynik) jeśli m: zwraca m.group („wiersze”), m.group („kolumny”) podnieść OSError („Zła odpowiedź:% s”% (wynik))
>>> Termsize () („40”, „100”)