在python中是否有一种方法以编程方式确定控制台的宽度?我指的是一行中不换行的字符数,而不是窗口的像素宽度。

Edit

寻找在Linux上工作的解决方案


当前回答

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

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

其他回答

use

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

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

编辑:哦,对不起。这不是python标准库,这里是console.py的源代码(我不知道它来自哪里)。

该模块的工作方式似乎是这样的:它检查termcap是否可用,如果是。它使用了那个;如果不支持,它会检查终端是否支持特殊的ioctl调用,如果不支持,它也会检查一些shell为此导出的环境变量。 这可能只适用于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和Solaris兼容的版本。根据来自madchine的帖子和评论。需要子流程模块。

def termsize():
    import shlex, subprocess, re
    output = subprocess.check_output(shlex.split('/bin/stty -a'))
    m = re.search('rows\D+(?P\d+); columns\D+(?P\d+);', output)
    if m:
        return m.group('rows'), m.group('columns')
    raise OSError('Bad response: %s' % (output))
>>> termsize()
('40', '100')

如果您使用的是Python 3.3或更高版本,我建议使用内置的get_terminal_size()。但是,如果您使用的是旧版本,想要一种简单的、跨平台的方式,那么可以使用asciimatics。这个包支持2.7以下的Python版本,并使用与上面建议的选项类似的选项来获取当前终端/控制台大小。

简单地构造Screen类并使用dimensions属性获取高度和宽度。这已经在Linux、OSX和Windows上被证明是有效的。

哦,在这里完全披露:我是作者,所以如果你在这方面有任何问题,请随时打开一个新的问题。

试着“祝福”

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

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

在Linux中工作就像一个魅力。(我不确定MacOSX和Windows)

在此下载及文件

或者你可以用pip安装它:

pip install blessings

如果在调用此脚本时没有控制终端,那么这里的许多Python 2实现都将失败。您可以检查sys.stdout.isatty()来确定这是否实际上是一个终端,但这将排除一些情况,因此我认为最python化的方法来计算终端大小是使用内置的curses包。

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