当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何在Python中获取Linux控制台窗口宽度》经验,为你挑选了9个好方法。

有没有办法在python中以编程方式确定控制台的宽度?我的意思是在没有包装的情况下适合一行的字符数,而不是窗口的像素宽度.

编辑

寻找适用于Linux的解决方案



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

使用'stty size'命令,根据python邮件列表中的一个线程,它在Linux上是合理通用的.它将'stty size'命令作为文件打开,从中读取',并使用简单的字符串拆分来分隔坐标.

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


`rows,columns = subprocess.check_output(['stty','size']).split()`稍短,加上子进程就是未来
默认情况下,不会在Bash中导出COLUMNS,这就是os.environ ["COLUMNS"]不起作用的原因.
tput优于stty,因为stty不能与PIPE一起使用.
`rows,columns = subprocess.check_output(['stty','size']).decode().split()`如果你想要unicode字符串兼容py2/3

2> Gringo Suave..:

不知道为什么它在模块中shutil,但是它在Python 3.3中找到了,查询输出终端的大小:

>>> 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:

https://pypi.python.org/pypi/backports.shutil_get_terminal_size


那是因为你不应该再使用2.7了,跳到3.x是值得的.
@osirisgothra许多托管服务提供商还不支持python3,因此我们中的一些人被迫使用python2进行后端开发.虽然这应该与获得终端大小无关......
@osirisgothra因为有很多Python 2代码需要花费太多的工作才能移植.此外,Pypy仍然有相当差的Python 3支持.
@whitebeard订户无法在VPS上安装Python 3吗?或者在2016年,人们仍在使用管理员不愿意安装Python 3的共享主机吗?例如,WebFaction共享主机安装了"python3.5".
对于从文件重定向标准输入时也能正常工作的解决方案的+1!使用其他解决方案,我要么得到"不恰当的ioctl for device"错误/警告,要么得到定义的回退值80.

3> Johannes Wei..:

使用

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

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

编辑:哦,对不起.这不是一个python标准的lib,这里是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])


感谢您的快速回复,但是在这里(http://effbot.org/zone/console-handbook.htm)它说"控制台模块目前仅适用于Windows 95,98,NT和2000." 我正在寻找适用于Linux的解决方案.从标签中可能不清楚,我会相应地编辑问题.
哦,而不是堆积在代码上,但"cr"是一个令人困惑的名字,因为它暗示元组是(cols,rows).实际上,情况正好相反.
因为你使用的这个"控制台"模块不在标准的python库上,所以你应该提供它的源代码或者至少提供它的链接.

4> 小智..:

上面的代码没有在我的linux上返回正确的结果,因为winsize-struct有4个unsigned 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

hp和hp应包含像素宽度和高度,但不包含.


这是应该怎么做的; 请注意,如果您打算打印到终端,则应使用"1"作为文件描述符(ioctl的第一个参数),因为stdin可能是管道或某些不同的tty.
这是最好的答案 - 您的用户会很高兴为了获得术语宽度而没有出现意外的子流程
这确实是最干净的答案.我认为你应该使用`stdout`或`stderr`而不是`stdin`.`stdin`很可能是一个管道.您可能还想添加一行,例如`if not os.isatty(0):return float("inf")`.

5> Harco Kuppen..:

我四处搜索,找到了一个Windows解决方案:

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



6> Granitosauru..:

它是:

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参数是有意义的并且不知道为什么它默认在这里.


`os.get_terminal_size()`是在Python 3.3中引入的

7> Bob Enohp..:

从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


```shutil.get_terminal_size()是通常应该使用的高级函数,os.get_terminal_size是低级实现.``

8> thejoshwolfe..:

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

getTerminalSize 需要 import os

是什么env?看起来像os.environ.

另外,为什么切换linescols返回前?如果TIOCGWINSZstty都表示,lines然后cols,我说离开这种方式.在我注意到不一致之前,这让我困惑了10分钟.

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

pascal,"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> wonton..:

如果在调用此脚本时没有控制终端,则此处的许多Python 2实现都将失败.您可以检查sys.stdout.isatty()以确定它是否实际上是一个终端,但这将排除一堆案例,所以我认为找出终端大小的最pythonic方法是使用builtin curses包.

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

推荐阅读
mobiledu2402851173
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有