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

发布于 2024-07-13 17:37:15 字数 107 浏览 8 评论 0原文

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

编辑

寻找适用于Linux的解决方案

Is there a way in python to programmatically determine the width of the console? I mean the number of characters that fits in one line without wrapping, not the pixel width of the window.

Edit

Looking for a solution that works on Linux

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

幻梦 2024-07-20 17:37:16

看起来该代码有一些问题,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)

It looks like there are some problems with that code, Johannes:

  • getTerminalSize needs to import os
  • what is env? looks like os.environ.

Also, why switch lines and cols before returning? If TIOCGWINSZ and stty both say lines then cols, I say leave it that way. This confused me for a good 10 minutes before I noticed the inconsistency.

Sridhar, I didn't get that error when I piped output. I'm pretty sure it's being caught properly in the try-except.

pascal, "HHHH" doesn't work on my machine, but "hh" does. I had trouble finding documentation for that function. It looks like it's platform dependent.

chochem, incorporated.

Here's my version:

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)
£冰雨忧蓝° 2024-07-20 17:37:16

如果调用此脚本时没有控制终端,则此处的许多 Python 2 实现都会失败。 您可以检查 sys.stdout.isatty() 来确定这实际上是否是一个终端,但这会排除很多情况,所以我相信计算终端大小的最Pythonic方法是使用内置的curses包。

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

Many of the Python 2 implementations here will fail if there is no controlling terminal when you call this script. You can check sys.stdout.isatty() to determine if this is in fact a terminal, but that will exclude a bunch of cases, so I believe the most pythonic way to figure out the terminal size is to use the builtin curses package.

import curses
w = curses.initscr()
height, width = w.getmaxyx()
莫相离 2024-07-20 17:37:16

尝试“祝福”

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

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

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

下载和文档此处

或者您可以安装它与点:

pip install blessings

Try "blessings"

I was looking for the very same thing. It is very easy to use and offers tools for coloring, styling and positioning in the terminal. What you need is as easy as:

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

Works like a charm in Linux. (I'm not sure about MacOSX and Windows)

Download and documentation here

or you can install it with pip:

pip install blessings
记忆里有你的影子 2024-07-20 17:37:16

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

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

但是这对我来说失败了,因为我正在编写一个需要在 stdin 上重定向输入的脚本,并且 stty 会在这种情况下抱怨“stdin 不是终端”。

我能够让它像这样工作:

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

I was trying the solution from here that calls out to stty size:

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

However this failed for me because I was working on a script that expects redirected input on stdin, and stty would complain that "stdin isn't a terminal" in that case.

I was able to make it work like this:

with open('/dev/tty') as tty:
    height, width = subprocess.check_output(['stty', 'size'], stdin=tty).split()
凡间太子 2024-07-20 17:37:16

如果您使用的是 Python 3.3 或更高版本,我建议您使用已推荐的内置 get_terminal_size() 。 但是,如果您坚持使用旧版本并想要一种简单的跨平台方式来执行此操作,您可以使用 asciimatics< /a>. 该包支持自 2.7 起的 Python 版本,并使用与上面建议的类似选项来获取当前终端/控制台大小。

只需构造您的 Screen 类并使用 dimensions 属性即可获取高度和宽度。 这已被证明可以在 Linux、OSX 和 Windows 上运行。

哦 - 在这里全面披露:我是作者,所以如果您在使用时遇到任何问题,请随时打开一个新问题。

If you're using Python 3.3 or above, I'd recommend the built-in get_terminal_size() as already recommended. However if you are stuck with an older version and want a simple, cross-platform way of doing this, you could use asciimatics. This package supports versions of Python back to 2.7 and uses similar options to those suggested above to get the current terminal/console size.

Simply construct your Screen class and use the dimensions property to get the height and width. This has been proven to work on Linux, OSX and Windows.

Oh - and full disclosure here: I am the author, so please feel free to open a new issue if you have any problems getting this to work.

牛↙奶布丁 2024-07-20 17:37:16

使用subprocess,这是最方便的方法:

导入:

import subprocess

使用示例:

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

注意:此函数返回字节,但您可以使用 int() 函数将其转换为 Integer。

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

输出:

[b'46', b'188']

例如,如果您需要比较控制台的宽度是否大于 W,您可以执行以下操作:

if int(subprocess.check_output(['stty', 'size']).split()[1]) > W:
    ...

Use subprocess, it is the most convenient way of doing it:

Import:

import subprocess

Example of Use:

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

Note: This function returns bytes but you can cast it to Integer with the int() function.

Note: this function returns an array, being: array[0]=rows and array[1]=columns.

Output:

[b'46', b'188']

For instance if you need to compare whether the width of your console is larger than W, you can do something like this:

if int(subprocess.check_output(['stty', 'size']).split()[1]) > W:
    ...

剩一世无双 2024-07-20 17:37:16

@reannual的答案效果很好,但有一个问题: os.popen 现已弃用。 应该使用 subprocess 模块,因此这里是 @reannual 代码的一个版本,它使用 subprocess 并直接回答问题(通过直接将列宽度作为 int

import subprocess

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

在 OS X 10.9 上测试

@reannual's answer works well, but there's an issue with it: os.popen is now deprecated. The subprocess module should be used instead, so here's a version of @reannual's code that uses subprocess and directly answers the question (by giving the column width directly as an int:

import subprocess

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

Tested on OS X 10.9

东走西顾 2024-07-20 17:37:16

这是一个应该与 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')

Here is an version that should be Linux and Solaris compatible. Based on the posts and commments from madchine. Requires the subprocess module.

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')
淤浪 2024-07-20 17:37:15

不知道为什么它在 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 模块中。 跨平台——可在 Linux、Mac OS 和 Windows 下运行,也可能在其他类 Unix 系统下运行。 还有一个向后移植,尽管不再相关。

Not sure why it is in the module shutil, but it landed there in Python 3.3. See:

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

A low-level implementation is in the os module. Cross-platform—works under Linux, Mac OS, and Windows, probably other Unix-likes. There's a backport as well, though no longer relevant.

浅浅 2024-07-20 17:37:15
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"]值仅在 python 解释器启动时有效(假设用户从那时起调整了窗口大小)。

(有关如何在 python 3.3+ 上执行此操作的信息,请参阅@GringoSuave 的回答)

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

uses the 'stty size' command which according to a thread on the python mailing list is reasonably universal on linux. It opens the 'stty size' command as a file, 'reads' from it, and uses a simple string split to separate the coordinates.

Unlike the os.environ["COLUMNS"] value (which I can't access in spite of using bash as my standard shell) the data will also be up-to-date whereas I believe the os.environ["COLUMNS"] value would only be valid for the time of the launch of the python interpreter (suppose the user resized the window since then).

(See answer by @GringoSuave on how to do this on python 3.3+)

空心空情空意 2024-07-20 17:37:15

使用

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])

use

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

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

EDIT: oh, I'm sorry. That's not a python standard lib one, here's the source of console.py (I don't know where it's from).

The module seems to work like that: It checks if termcap is available, when yes. It uses that; if no it checks whether the terminal supports a special ioctl call and that does not work, too, it checks for the environment variables some shells export for that.
This will probably work on UNIX only.

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])
撞了怀 2024-07-20 17:37:15

上面的代码在我的 Linux 上没有返回正确的结果,因为 winsize-struct 有 4 个无符号的 Shorts,而不是 2 个有符号的 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 应该包含像素宽度和高度,但没有。

Code above didn't return correct result on my linux because winsize-struct has 4 unsigned shorts, not 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 and hp should contain pixel width and height, but don't.

混浊又暗下来 2024-07-20 17:37:15

它是:

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

It's either:

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

The shutil function is just a wrapper around os one that catches some errors and set up a fallback, however it has one huge caveat - it breaks when piping!, which is a pretty huge deal.
To get terminal size when piping use os.get_terminal_size(0) instead.

First argument 0 is an argument indicating that stdin file descriptor should be used instead of default stdout. We want to use stdin because stdout detaches itself when it is being piped which in this case raises an error.

I've tried to figure out when would it makes sense to use stdout instead of stdin argument and have no idea why it's a default here.

鹿港巷口少年归 2024-07-20 17:37:15

我四处搜索并找到了 Windows 的解决方案:

http:// code.activestate.com/recipes/440694-define-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

I searched around and found a solution for windows at :

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

and a solution for linux here.

So here is a version which works both on linux, os x and 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
风月客 2024-07-20 17:37:15

从 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

Starting at Python 3.3 it is straight forward:
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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文