簡體   English   中英

如何在 Python 中獲取 Linux 控制台窗口寬度

[英]How to get Linux console window width in Python

python中有沒有辦法以編程方式確定控制台的寬度? 我的意思是一行中沒有換行的字符數,而不是窗口的像素寬度。

編輯

尋找適用於 Linux 的解決方案

不知道為什么它在模塊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 模塊中有一個低級實現。 也適用於 Windows。

現在可用於 Python 3.2 及以下版本的反向移植:

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

使用 'stty size' 命令,根據python 郵件列表上的一個線程,該命令在 linux 上相當普遍。 它將“stty size”命令作為文件打開,從中“讀取”,並使用簡單的字符串拆分來分隔坐標。

與 os.environ["COLUMNS"] 值(盡管使用 bash 作為我的標准外殼我無法訪問)不同,數據也將是最新的,而我相信 os.environ["COLUMNS"] value 僅在 python 解釋器啟動時有效(假設用戶從那時起調整了窗口大小)。

(請參閱@GringoSuave 關於如何在 python 3.3+ 上執行此操作的答案)

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 上沒有返回正確的結果,因為 winsize-struct 有 4 個無符號的短褲,而不是 2 個有符號的短褲:

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 應該包含像素寬度和高度,但不要。

它是:

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

shutil函數只是os one 的一個包裝器,它可以捕獲一些錯誤並設置回退,但是它有一個巨大的警告 -它在管道時會中斷! ,這是一個相當大的交易。
要在管道使用os.get_terminal_size(0)時獲取終端大小。

第一個參數0是一個參數,指示應該使用標准輸入文件描述符而不是默認標准輸出。 我們想使用 stdin,因為 stdout 在它被管道傳輸時會自行分離,在這種情況下會引發錯誤。

我試圖弄清楚什么時候使用 stdout 而不是 stdin 參數才有意義,但不知道為什么它是這里的默認值。

我四處搜索並在以下位置找到了適用於 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

從 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

看起來那個代碼有一些問題,約翰內斯:

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

另外,為什么開關linescols返回前? 如果TIOCGWINSZstty都說lines然后cols ,我說就這樣吧。 在我注意到不一致之前,這讓我困惑了 10 分鍾。

Sridhar,當我通過管道輸出時,我沒有收到那個錯誤。 我很確定它在 try-except 中被正確捕獲。

pascal, "HHHH"在我的機器上不起作用,但"hh"可以。 我無法找到該功能的文檔。 看起來它依賴於平台。

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)

如果在調用此腳本時沒有控制終端,此處的許多 Python 2 實現將失敗。 您可以檢查 sys.stdout.isatty() 以確定這是否實際上是一個終端,但這將排除一堆情況,所以我相信確定終端大小的最pythonic方法是使用內置的curses包。

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

我正在嘗試從這里調用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()

試試“祝福”

我一直在尋找同樣的東西。 它非常易於使用,並提供用於在終端中着色、造型和定位的工具。 您需要的很簡單:

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

在 Linux 中就像一個魅力。 (我不確定 MacOSX 和 Windows)

下載和文檔在這里

或者您可以使用 pip 安裝它:

pip install blessings

如果您使用的是 Python 3.3 或更高版本,我建議您使用已經推薦的內置get_terminal_size() 但是,如果您堅持使用舊版本並想要一種簡單的跨平台方式來執行此操作,則可以使用asciimatics 這個包支持 Python 版本回到 2.7 並使用與上面建議的選項類似的選項來獲取當前的終端/控制台大小。

只需構建您的Screen類並使用dimensions屬性來獲取高度和寬度。 這已被證明適用於 Linux、OSX 和 Windows。

哦 - 在這里完全公開:我是作者,所以如果您在使用它時遇到任何問題,請隨時打開一個新問題。

@reannual 的答案很有效,但它有一個問題: os.popen現在已棄用 subprocess模塊應改為使用,所以這里的@ reannual的代碼,使用一個版本的subprocess ,直接回答了這個問題(通過直接向列寬為int

import subprocess

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

在 OS X 10.9 上測試

這是一個應該與 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')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM