307

Pythonでコンソールの幅をプログラムで決定する方法はありますか? ウィンドウのピクセル幅ではなく、折り返しなしで 1 行に収まる文字数を意味します。

編集

Linuxで動作するソリューションを探しています

4

14 に答える 14

319

モジュールにある理由はわかりません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 以下で利用できるようになりました:

于 2013-01-20T07:25:34.203 に答える
276
import os
rows, columns = os.popen('stty size', 'r').read().split()

Pythonメーリングリストのスレッドによると、 Linuxではかなり普遍的な「stty size」コマンドを使用します。「stty size」コマンドをファイルとして開き、そこから「読み取り」、単純な文字列分割を使用して座標を分離します。

os.environ["COLUMNS"] の値 (標準シェルとして bash を使用しているにもかかわらずアクセスできない) とは異なり、データも最新のものになりますが、os.environ["COLUMNS"] は値は、Python インタープリターの起動時にのみ有効です (それ以降、ユーザーがウィンドウのサイズを変更したとします)。

(python 3.3+でこれを行う方法については、@GringoSuaveの回答を参照してください)

于 2009-06-03T09:59:34.893 に答える
66

使用する

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

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

編集:ああ、ごめんなさい。これはpython標準のlibのものではありません。console.pyのソースは次のとおりです(どこから来たのかわかりません)。

モジュールはそのように動作するようです:termcap利用可能かどうかを確認します。それを使用します。いいえの場合、端末が特別な呼び出しをサポートしているかどうかを確認しioctlますが、それも機能しません。一部のシェルがそのためにエクスポートする環境変数を確認します。これはおそらく 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])
于 2009-02-19T19:18:11.190 に答える
59

winsize-struct には 2 つの署名付き short ではなく、4 つの unsigned short があるため、上記のコードは私の Linux では正しい結果を返しませんでした。

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 には、ピクセルの幅と高さを含める必要がありますが、含めないでください。

于 2010-06-09T22:36:38.127 に答える
39

私は周りを検索し、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
于 2011-07-01T16:23:02.727 に答える
6

ここでの Python 2 実装の多くは、このスクリプトを呼び出すときに制御端末がないと失敗します。sys.stdout.isatty() をチェックして、これが実際に端末であるかどうかを判断できますが、それでは多くのケースが除外されるため、端末のサイズを把握する最も Pythonic な方法は、組み込みの curses パッケージを使用することだと思います。

import curses
w = curses.initscr()
height, width = w.getmaxyx()
于 2016-05-31T22:26:04.610 に答える
6

そのコードにはいくつか問題があるようです、ヨハネス:

  • getTerminalSizeする必要があるimport os
  • は何envですか?のように見えos.environます。

また、なぜ戻る前に切り替えるlinesのですか?と両方が言うcolsなら、そのままにしておくと言います。これは、矛盾に気付く前に 10 分間混乱しました。TIOCGWINSZsttylinescols

Sridhar、出力をパイプしたときにそのエラーは発生しませんでした。try-exceptで適切にキャッチされていると確信しています。

"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)
于 2010-06-16T07:23:51.490 に答える
1

私はここから呼び出すソリューションを試していましたstty size

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

ただし、標準入力でリダイレクトされた入力を期待するスクリプトに取り組んでいたため、これは失敗しましたstty。その場合、「標準入力は端末ではありません」と不平を言うでしょう。

私はそれを次のように機能させることができました:

with open('/dev/tty') as tty:
    height, width = subprocess.check_output(['stty', 'size'], stdin=tty).split()
于 2014-09-08T18:36:32.630 に答える
0

@reannual の回答はうまく機能しますが、問題があります: os.popen is now deprecated . subprocess代わりにモジュールを使用する必要があるため、@reannual のコードを使用subprocessして質問に直接回答するバージョンを次に示します (列幅をint:

import subprocess

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

OS X 10.9 でテスト済み

于 2014-07-22T18:30:16.880 に答える
-1

これは、Linux および Solaris と互換性のあるバージョンです。madchine からの投稿とコメントに基づいています。subprocess モジュールが必要です。

def termsize():
    import shlex、サブプロセス、re
    output = subprocess.check_output(shlex.split('/bin/stty -a'))
    m = re.search('行\D+(?P\d+); 列\D+(?P\d+);', 出力)
    もしm:
        return m.group('rows'), m.group('columns')
    raise OSError('Bad response: %s' % (出力))
>>> タームサイズ()
('40', '100')
于 2011-04-19T03:33:30.757 に答える