代码之家  ›  专栏  ›  技术社区  ›  Sergey Golovchenko

如何在Python中获取Linux控制台窗口宽度

  •  324
  • Sergey Golovchenko  · 技术社区  · 17 年前

    编辑

    寻找适用于Linux的解决方案

    15 回复  |  直到 9 年前
        1
  •  304
  •   Gringo Suave    6 年前

    shutil ,但它在Python 3.3中实现了。请参阅:

    Querying the size of the output terminal

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

    操作系统模块中有一个低级实现。跨平台在Linux、Mac OS和Windows下工作,可能还有其他类Unix。还有一个后门,虽然不再相关。

        2
  •  274
  •   boxed    6 年前
    import os
    rows, columns = os.popen('stty size', 'r').read().split()
    

    使用“stty size”命令,根据 a thread on the python mailing list 在linux上是相当通用的。它将“stty size”命令作为文件打开,从中“读取”,并使用简单的字符串分割来分隔坐标。

    与os.environ[“COLUMNS”]值不同(尽管我使用bash作为标准shell,但我无法访问它),数据也将是最新的,而我相信os.envilon[“COLLUMNS”]的值只在python解释器启动时有效(假设用户从那以后调整了窗口的大小)。

        3
  •  66
  •   chown    13 年前

    import console
    (width, height) = console.getTerminalSize()
    
    print "Your terminal's width is: %d" % width
    

    编辑

    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])
    
        4
  •  59
  •   pascal    16 年前

    上面的代码在我的linux上没有返回正确的结果,因为winsize结构体有4个无符号short,而不是2个有符号short:

    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
    

        5
  •  45
  •   jamesdlin    6 年前

    要么:

    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参数是有意义的,但不知道为什么它在这里是默认值。

        6
  •  39
  •   Harco Kuppens    15 年前

    我四处寻找,找到了windows的解决方案:

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

    所以这里有一个在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
    
        7
  •  22
  •   Bob Enohp    12 年前

    从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
    
        8
  •  6
  •   thejoshwolfe    16 年前

    看起来这段代码有一些问题,Johannes:

    • getTerminalSize 需要 import os
    • 是什么 env os.environ .

    另外,为什么要切换 lines cols 回来之前?如果 TIOCGWINSZ stty 线条 ,我说就这样吧。这让我困惑了整整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)
    
        9
  •  6
  •   wonton    10 年前

    import curses
    w = curses.initscr()
    height, width = w.getmaxyx()
    
        10
  •  1
  •   Marc Liyanage    11 年前

    尝试

    我在找同样的东西。它非常易于使用,并提供了在终端中着色、造型和定位的工具。你需要的是简单的:

    from blessings import Terminal
    
    t = Terminal()
    
    w = t.width
    h = t.height
    

    在Linux中工作起来很有魅力。(我不确定MacOSX和Windows)

    下载和文档 here

    pip install blessings
    
        11
  •  1
  •   Iman Akbari    11 年前

    stty size

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

    然而,这对我来说失败了,因为我正在编写一个脚本,该脚本要求在stdin上重定向输入,并且 stty

    with open('/dev/tty') as tty:
        height, width = subprocess.check_output(['stty', 'size'], stdin=tty).split()
    
        12
  •  1
  •   Peter Brittain    10 年前

    如果你使用的是Python 3.3或更高版本,我建议使用内置 get_terminal_size() asciimatics

    Screen 类和使用 dimensions

    哦,在这里完全披露:我是作者,所以如果你在实现这一点上有任何问题,请随时打开一期新杂志。

        13
  •  0
  •   rickcnagy    12 年前

    使用 subprocess

    导入:

    import subprocess
    

    使用示例:

    print(subprocess.check_output(['stty', 'size']).split())
    

    int()

    注意:此函数返回一个数组,即: array[0] = array[1] = .

    输出:

    [b'46', b'188']
    

    W ,你可以这样做:

    if int(subprocess.check_output(['stty', 'size']).split()[1]) > W:
        ...
    
    
        14
  •  -1
  •   Community Mohan Dere    9 年前

    @reanual的答案很好,但有一个问题: os.popen is now deprecated The subprocess 应该使用模块,所以这是@reanual代码的一个版本,它使用 子进程 并直接回答问题(通过直接将列宽作为 int

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