328 votes

Comment obtenir la largeur de la fenêtre de la console Linux en Python

Existe-t-il un moyen en python de déterminer de manière programmatique la largeur de la console ? Je veux dire le nombre de caractères qui tiennent sur une ligne sans s'enrouler, pas la largeur en pixels de la fenêtre.

Editar

Recherche d'une solution qui fonctionne sous Linux

0 votes

Regardez cette réponse pour une solution plus étendue pour avoir un mécanisme d'impression "dépendant des colonnes". stackoverflow.com/questions/44129613/

2 votes

Veuillez envisager de changer la réponse acceptée. Celle que vous avez choisie est vraiment bancale, dépendante de la plateforme, et elle utilise os.popen qui est déprécié. La réponse la plus votée montre shutil est le meilleur moyen.

342voto

Gringo Suave Points 5985

Je ne sais pas pourquoi il est dans le module shutil mais il a atterri là dans Python 3.3, Interrogation de la taille de la borne de sortie :

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

Une implémentation de bas niveau se trouve dans le module os. Fonctionne également sous Windows.

Un backport est maintenant disponible pour Python 3.2 et inférieur :

1 votes

Bien trouvé, mais ça n'a jamais été mis dans la 2.7, il semble.

37 votes

C'est parce que vous ne devriez plus utiliser la version 2.7, faites le saut vers la version 3.x, cela en vaut la peine.

1 votes

C'est tout simplement la façon dont cela devrait être fait. Il est même mis à jour lorsque la largeur de la console change. +1

281voto

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

utilise la commande 'stty size' qui, selon la norme un fil de discussion sur la liste de diffusion python est raisonnablement universel sous linux. Il ouvre la commande 'stty size' comme un fichier, le 'lit', et utilise une simple séparation de chaîne pour séparer les coordonnées.

Contrairement à la valeur os.environ["COLUMNS"] (à laquelle je ne peux pas accéder malgré l'utilisation de bash comme shell standard), les données seront également à jour alors que je pense que la valeur os.environ["COLUMNS"] ne serait valable que pour le moment du lancement de l'interpréteur python (supposons que l'utilisateur ait redimensionné la fenêtre depuis).

(Voir la réponse de @GringoSuave sur la façon de faire cela sur python 3.3+)

1 votes

Vous pouvez également faire fonctionner cette méthode sur Solaris si, au lieu de "size", vous passez "-a". Il y aura "rows = Y ; columns = X" dans la sortie délimitée par des points-virgules.

0 votes

Testé sur Ubuntu, il semble que -a fonctionne aussi sur Linux mais la sortie est formatée légèrement différemment -- il n'y a pas de '=' entre les lignes/colonnes et le nombre.

5 votes

COLUMNS n'est pas exporté par défaut dans Bash, c'est pourquoi os.environ["COLUMNS"] ne fonctionne pas.

67voto

Johannes Weiß Points 19013

Utiliser

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

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

EDITAR : oh, je suis désolé. Ce n'est pas une librairie standard de python, voici la source de console.py (je ne sais pas d'où elle vient).

Le module semble fonctionner ainsi : Il vérifie si termcap est disponible, si oui. Il l'utilise ; si non, il vérifie si le terminal supporte une option spéciale de l'interface utilisateur. ioctl et cela ne fonctionne pas non plus, il vérifie les variables d'environnement que certains shells exportent pour cela. Cela ne fonctionnera probablement que sur 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])

5 votes

Merci pour la réponse rapide, mais ici ( effbot.org/zone/console-handbook.htm ), il est indiqué que "le module Console n'est actuellement disponible que pour Windows 95, 98, NT et 2000". Je suis à la recherche d'une solution qui fonctionne sous Linux. Ce n'était probablement pas clair dans la balise, je vais modifier la question en conséquence.

2 votes

Comme le module "console" que vous utilisez ne fait pas partie de la bibliothèque python standard, vous devriez fournir son code source ou au moins un lien vers celui-ci.

0 votes

Je suis désolé pour ça. En fait, je ne connaissais pas ce module. J'ai essayé d'importer console et ça a marché, j'ai utilisé console.<tab><tab> et getTerminalSize() est apparu. Au lieu de chercher d'où ça vient, j'ai déjà posté une réponse parce que j'ai eu la chance que ce soit simple. g

62voto

pascal Points 221

Le code ci-dessus n'a pas retourné le bon résultat sur mon linux parce que la structure winsize a 4 shorts non signés, et non 2 shorts signés :

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 et hp devraient contenir la largeur et la hauteur des pixels, mais ne le font pas.

4 votes

C'est ainsi qu'il faut procéder ; notez que si vous avez l'intention d'imprimer sur le terminal, vous devez utiliser '1' comme descripteur de fichier (premier argument de ioctl), car stdin peut être un pipe ou un autre tty.

1 votes

Peut-être que le 0 devrait être remplacé par fcntl.ioctl(sys.stdin.fileno(), ...

4 votes

C'est la meilleure réponse - vos utilisateurs seront heureux qu'il n'y ait pas un sous-processus surprise qui se déroule juste pour obtenir la largeur du terme.

40voto

Harco Kuppens Points 181

J'ai cherché et trouvé une solution pour Windows à :

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

et une solution pour linux ici.

Voici donc une version qui fonctionne à la fois sur linux, os x et 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

0 votes

Vous m'avez épargné le temps de le faire moi-même. Fonctionne sur Linux. Devrait aussi fonctionner sous Windows. Merci !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X