it-swarm.com.de

So erhalten Sie die Breite des Linux-Konsolenfensters in Python

Gibt es eine Möglichkeit in python programmgesteuert die Breite der Konsole zu bestimmen? Ich meine die Anzahl der Zeichen, die in eine Zeile ohne Zeilenumbruch passen, nicht die Pixelbreite des Fensters.

Bearbeiten

Auf der Suche nach einer Lösung, die unter Linux funktioniert

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

verwendet den Befehl 'stty size', der laut einem Thread auf der python mailing list unter Linux ziemlich universell ist. Er öffnet den Befehl 'stty size' als Datei , 'liest' daraus und trennt die Koordinaten mit einer einfachen Zeichenfolge.

Im Gegensatz zum Wert os.environ ["COLUMNS"] (auf den ich trotz der Verwendung von bash als meine Standard-Shell nicht zugreifen kann) sind die Daten auch aktuell, während ich der Ansicht bin, dass os.environ ["COLUMNS"] value ist nur zum Zeitpunkt des Starts des python interpreter) gültig (angenommen, der Benutzer hat die Größe des Fensters seitdem geändert).

240
brokkr

Nicht sicher, warum es im Modul shutil ist, aber es ist dort gelandet in Python 3.3, Abfragen der Größe des Ausgabe-Terminals :

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

Eine Low-Level-Implementierung befindet sich im Modul os.

Für Python 3.2 und niedriger ist jetzt ein Backport verfügbar:

223
Gringo Suave

verwenden

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

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

EDIT : Oh, tut mir leid. Dies ist keine python Standardbibliothek, hier ist die Quelle von console.py (ich weiß nicht, woher es kommt).

Das Modul scheint so zu funktionieren: Es prüft, ob termcap verfügbar ist, wenn ja. Es benutzt das; Wenn nein, prüft es, ob das Terminal einen speziellen ioctl -Aufruf unterstützt, und das funktioniert auch nicht, prüft es, ob die Umgebungsvariablen von einigen Shells dafür exportiert wurden. Dies funktioniert wahrscheinlich nur unter 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])
65
Johannes Weiss

Der obige Code lieferte auf meinem Linux kein korrektes Ergebnis, da winsize-struct 4 nicht signierte Shorts und keine 2 signierten Shorts hat:

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 und hp sollten Pixelbreite und -höhe enthalten, aber nicht.

54
pascal

Ich habe mich umgesehen und eine Lösung für Windows gefunden:

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

und eine lösung für linux hier.

Hier ist eine Version, die sowohl unter Linux, OS X als auch unter Windows/Cygwin funktioniert:

""" 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 __== "__main__":
    sizex,sizey=getTerminalSize()
    print  'width =',sizex,'height =',sizey
38
Harco Kuppens

Ab Python 3.3 ist es ganz einfach: 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
16
Bob Enohp

Es ist entweder:

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

Die shutil -Funktion ist nur ein Wrapper um os, der einige Fehler abfängt und einen Fallback einrichtet, hat jedoch einen großen Nachteil - sie bricht beim Piping ab! Das ist eine ziemlich große Sache.
Verwenden Sie stattdessen os.get_terminal_size(0), um die Klemmengröße beim Leiten zu ermitteln.

Das erste Argument 0 Ist ein Argument, das angibt, dass anstelle des Standard-stdout der stdin-Dateideskriptor verwendet werden soll. Wir wollen stdin verwenden, weil stdout sich während der Pipeline-Verarbeitung von selbst löst und in diesem Fall einen Fehler auslöst.
Ich habe versucht herauszufinden, wann es Sinn macht, stdout anstelle des stdin-Arguments zu verwenden, und habe keine Ahnung, warum es hier eine Standardeinstellung ist.

14
Granitosaurus

Es sieht so aus, als gäbe es einige Probleme mit diesem Code, Johannes:

  • getTerminalSize muss import os
  • was ist env? sieht aus wie os.environ.

Warum sollten Sie lines und cols wechseln, bevor Sie zurückkehren? Wenn TIOCGWINSZ und stty beide lines sagen, dann cols, dann sage ich, lass es so. Dies verwirrte mich gut 10 Minuten, bevor ich die Inkonsistenz bemerkte.

Sridhar, ich habe diesen Fehler nicht erhalten, als ich die Ausgabe weitergeleitet habe. Ich bin mir ziemlich sicher, dass es beim Versuch richtig erwischt wird - außer.

Pascal, "HHHH" funktioniert nicht auf meinem Computer, aber "hh" tut. Ich konnte keine Dokumentation für diese Funktion finden. Es scheint plattformabhängig zu sein.

chochem, eingearbeitet.

Hier ist meine Version:

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)
6
thejoshwolfe

Viele der Python 2-Implementierungen hier schlagen fehl, wenn beim Aufrufen dieses Skripts kein steuerndes Terminal vorhanden ist. Sie können sys.stdout.isatty () überprüfen, um festzustellen, ob es sich tatsächlich um ein Terminal handelt. Aber das schließt eine Reihe von Fällen aus. Ich glaube, der beste Weg, um die Terminalgröße herauszufinden, ist die Verwendung des eingebauten Curses-Pakets.

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

Ich habe die Lösung ausprobiert, die stty size:

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

Dies schlug jedoch fehl, da ich an einem Skript arbeitete, das umgeleitete Eingaben für stdin erwartet, und stty beschwerte sich, dass "stdin kein Terminal" ist.

Ich konnte es so machen:

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

Wenn Sie Python 3.3 oder höher) verwenden, würde ich die integrierte Funktion get_terminal_size() wie bereits empfohlen empfehlen Um dies auf einfache Weise plattformübergreifend zu tun, können Sie asciimatics verwenden. Dieses Paket unterstützt Versionen von Python zurück zu 2.7 und verwendet ähnliche Optionen wie die oben vorgeschlagenen, um diese zu erhalten die aktuelle Terminal-/Konsolengröße.

Erstellen Sie einfach Ihre Klasse Screen und verwenden Sie die Eigenschaft dimensions, um die Höhe und Breite abzurufen. Dies funktioniert nachweislich unter Linux, OSX und Windows.

Oh - und vollständige Offenlegung hier: Ich bin der Autor, also zögern Sie nicht, eine neue Ausgabe zu eröffnen, wenn Sie Probleme haben, dies zum Laufen zu bringen.

1
Peter Brittain

Die Antwort von @reannual funktioniert gut, aber es gibt ein Problem damit: os.popenist jetzt veraltet . Das subprocess -Modul sollte stattdessen verwendet werden. Hier ist eine Version des Codes von @ reannual, die subprocess verwendet und die Frage direkt beantwortet (indem die Spaltenbreite direkt als int angegeben wird:

import subprocess

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

Getestet unter OS X 10.9

1
rickcnagy

Versuchen Sie "Segen"

Ich suchte genau das Gleiche. Es ist sehr einfach zu bedienen und bietet Werkzeuge zum Färben, Gestalten und Positionieren im Terminal. Was Sie brauchen, ist so einfach wie:

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

Funktioniert wie ein Zauber in Linux. (Ich bin mir nicht sicher über MacOSX und Windows)

Download und Dokumentation hier

oder du kannst es mit pip installieren:

pip install blessings
1
Iman Akbari

Hier ist eine Version, die mit Linux und Solaris kompatibel sein sollte. Basierend auf den Beiträgen und Kommentaren von madchine . Benötigt das Subprozessmodul.

 def termize (): 
 shlex, subprocess, re 
 output = subprocess.check_output (shlex.split ('/ bin/stty -a')) 
 m = re.search ('Zeilen\D + (? P\d +); Spalten\D + (? P\d +);', Ausgabe) 
 if m: 
 return m.group ( 'rows'), m.group ('columns') 
 OSError auslösen ('Bad response:% s'% (output)) 
 >>> termize () 
 ('40', '100') 
0
Derrick Petzold