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

有没有在python的方式来以编程方式确定控制台的宽度? 我的意思是适合在一行中没有换行的字符数,而不是窗口的像素宽度。

编辑

寻找一个适用于Linux的解决scheme

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

使用根据Python邮件列表上的线程在Linux上合理通用的“stty size”命令。 它将“stty size”命令作为文件打开,“读取”文件,并使用简单的string拆分来分隔坐标。

不像os.environ [“COLUMNS”]值(尽pipe使用bash作为我的标准shell,我无法访问),数据也将是最新的,而我相信os.environ [“COLUMNS”]值只会在python解释器启动的时候才有效(假设用户从此调整了窗口的大小)。

不知道为什么它在模块shutil ,但它在Python 3.3着陆, 查询输出terminal的大小 :

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

os模块中有一个低级的实现。

Python 3.2及以下版本现在可以使用backport:

使用

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

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

该模块似乎是这样工作的:它检查termcap是否可用,当是的。 它使用那个; 如果没有,它会检查terminal是否支持一个特殊的ioctl调用,并且不起作用,它会检查一些shell为此导出的环境variables。 这可能只适用于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上返回正确的结果,因为winsize-struct有4个unsigned shorts,而不是2个signed shorts:

 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和hp应该包含像素的宽度和高度,但不要。

我search了四周,发现窗口的解决scheme:

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

并在这里为Linux的解决scheme。

所以这里是一个在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 

从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 

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

  • getTerminalSize需要import os
  • 什么是env ? 看起来像os.environ

另外,为什么在返回之前切换lines和列? 如果TIOCGWINSZstty都说lines然后cols ,我说离开这个方式。 在我注意到不一致之前,这让我困惑了十分钟。

Sridhar,当我输出输出时,我没有得到那个错误。 我很确定它在try-except中被正确捕获。

帕斯卡尔, "HHHH"不能在我的机器上工作,但"hh" 。 我无法find该function的文档。 它看起来像是平台依赖。

chochem,注册成立。

这是我的版本:

 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) 

当你调用这个脚本时,如果没有控制terminal,这里的许多Python 2实现将会失败。 你可以检查sys.stdout.isatty()来确定它是否实际上是一个terminal,但是这将排除大量的情况,所以我相信找出terminal大小的最pythonic方法是使用内置的curses包。

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

它可以是:

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

shutil函数只是一个可以捕捉一些错误并设置回退的封装,但它有一个巨大的警告 – 当pipe道系统崩溃时! ,这是一个相当大的交易。
当pipe道使用os.get_terminal_size(0)时,要获得terminal大小。

第一个参数0是一个参数,指示应该使用stdin文件描述符而不是默认stdout,我们要使用stdin,因为stdout在被pipe道时会自行分离,并且出现错误。
我试图找出什么时候使用stdout而不是stdin参数是合理的,不知道为什么它是默认的。

我正在尝试从这里调用stty size的解决scheme:

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

然而,这对我来说是失败的,因为我正在研究一个脚本,它希望在stdin上redirectinput, stty会抱怨说“stdin不是terminal”。

我能够像这样工作:

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

尝试“祝福”

我正在寻找同样的东西。 这是非常容易使用,并提供terminal着色,造型和定位工具。 你需要的是如下简单:

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

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

在这里下载和文档

或者你可以用pip安装它:

 pip install blessings 

如果您使用的是Python 3.3或更高版本,我build议您使用内build的get_terminal_size() 。 但是,如果您遇到一个较旧的版本,并且想要一个简单的,跨平台的方式来执行此操作,则可以使用asciimatics 。 该软件包支持Python版本回到2.7,并使用类似的选项来获得当前的terminal/控制台大小。

只需构造你的Screen类并使用dimensions属性来获取高度和宽度。 这已经被certificate可以在Linux,OSX和Windows上运行。

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

这是一个应该兼容Linux和Solaris的版本。 根据madchine的post和评论 。 需要subprocess模块。

 def termsize():
    导入shlex,subprocess,re
     output = subprocess.check_output(shlex.split('/ bin / stty -a'))
     m = re.search('rows \ D +(?P \ d +); columns \ D +(?P \ d +);',output)
    如果m:
        返回m.group('行'),m.group('列')
    引发OSError('错误的响应:%s'%(输出))
 >>> termsize()
 ('40','100')

@ reannual的答案效果很好,但有一个问题: os.popen 现在被弃用 。 应该使用subprocess模块​​,所以这里是一个版本的@ reannual的代码,它使用subprocess进程,并直接回答问题(直接给列的宽度作为int

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

testing在OS X 10.9上