PythonでLinuxコンソールウィンドウの幅を取得する方法


264

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

編集する

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


「列に依存する」印刷メカニズムを持つより広範なソリューションについては、この回答を参照してください。stackoverflow.com/questions/44129613/...
リッカルドPetraglia

回答:


262
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の回答を参照してください)


1
「サイズ」の代わりに「-a」を渡すと、これをSolarisでも機能させることができます。セミコロンで区切られた出力には、「行= Y、列= X」があります。
ジョセフガービン

5
COLUMNSはデフォルトではBashにエクスポートされないため、os.environ ["COLUMNS"]は機能しません。
Kjell Andreassen

38
rows, columns = subprocess.check_output(['stty', 'size']).split()少し短く、さらにサブプロセスが未来
cdosborn 2015年

7
sttyはPIPEでは機能しないため、tputはsttyよりも優れています。
liuyang1 2015

5
rows, columns = subprocess.check_output(['stty', 'size']).decode().split()py2 / 3互換性のためにUnicode文字列が必要な場合
Bryce Guinta

264

なぜそれがモジュールにあるのかはわかりませんが、出力ターミナルのサイズをクエリ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以下で利用可能になりました:


25
これは、2.7をもう使用するべきではないためです。3.xへのジャンプを価値のあるものにします。
anthonyryan1 2015年

5
@osirisgothra多くのホスティングプロバイダーはまだpython3をサポートしていないため、バックエンド開発にpython2の使用を余儀なくされる人もいます。端末サイズの取得とは関係ありませんが
whitebeard

4
@osirisgothra移植に手間がかかりすぎるPython 2コードがたくさんあるからです。また、PypyはまだPython 3のサポートが不十分です。
アンチモン

2
@whitebeardサブスクライバーがVPSにPython 3をインストールできない理由はありますか?または、2016年に、管理者がPython 3をインストールしたくない共有ホスティングをまだ使用していますか?たとえば、WebFaction共有ホスティングがpython3.5インストールされています。
Damian Yerrick 2016年

2
標準入力がファイルからリダイレクトされたときにも機能するソリューションの+1!他のソリューションでは、私はどちらかになっていたInappropriate ioctl for deviceエラー/警告を、または80の定義されたフォールバック値を取得
pawamoy

65

使用する

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

5
迅速な回答に感謝しますが、ここ(effbot.org/zone/console-handbook.htm)には、「コンソールモジュールは現在、Windows 95、98、NT、および2000でのみ利用可能です」と記載されています。Linuxで動作するソリューションを探しています。おそらくタグから明確ではなかったので、それに応じて質問を編集します。
セルゲイゴロフチェンコ

2
使用しているこの「コンソール」モジュールは標準のPythonライブラリにないため、そのソースコードまたは少なくともリンクを提供する必要があります。
nosklo 2009

ごめんなさい。実際、そのモジュールは知りませんでした。インポートコンソールを試してみましたが、うまくいきました。<tab> <tab>とgetTerminalSize()が表示されました。代わりに、それはだところ、私はすでに答えを掲示から、私はシンプルさののとても幸運だったので、見ているのグラム
ヨハネス・ヴァイス

別の「コンソール」モジュールを見ている可能性があります。お持ちのモジュールのリンクを提供していただけませんか。
Sergey Golovchenko

4
ああ、コードを重ねる必要はありませんが、 "cr"は、タプルが(cols、rows)であることを意味するため、紛らわしい名前です。実際には、その逆です。
Paul Du Bois、

57

上記のコードは、winsize-structに2つの符号付きショートではなく4つの符号なしショートがあるため、私の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にはピクセルの幅と高さが含まれている必要がありますが、含まれていません。


4
これは、それを行う方法です。端末に出力する場合は、stdinがパイプまたは別のttyである可能性があるため、ファイル記述子(ioctlの最初の引数)として「1」を使用する必要があることに注意してください。
mic_e

1
おそらく0に置き換える必要がありますfcntl.ioctl(sys.stdin.fileno(), ...
raylu 2013

4
これが最良の答えです。ユーザーは、用語の幅を取得するためだけに発生する
予期し

4
これは確かに最もきれいな答えです。ただし、の代わりにstdoutまたはを使用する必要があると思います。パイプかもしれません。のような行を追加することもできます。stderrstdinstdinif not os.isatty(0): return float("inf")
mic_e 2014年

これはどういうわけか機能のないchromebook端末で動作します。+1
HyperNeutrino 2017年

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

あなたは私がこれを自分で行う時間を節約しました。Linuxで動作します。Windowsでも動作するはずです。ありがとう!
スティーブV.

30

次のいずれかです。

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

このshutil関数は、osいくつかのエラーをキャッチしてフォールバックを設定するラッパーにすぎませんが、大きな警告が1つあります- パイプすると壊れます!、これはかなり大きな取引です。
配管時の端子サイズを求めるにはos.get_terminal_size(0)代わりにご使用ください。

最初の引数0は、デフォルトのstdoutの代わりにstdinファイル記述子を使用する必要があることを示す引数です。stdinは、パイプ処理されているときに自身を切り離すため、stdinを使用します。この場合、エラーが発生します。

stdin引数の代わりにstdoutを使用することが理にかなっている場合を理解しようとしましたが、なぜこれがデフォルトであるのかわかりません。


3
os.get_terminal_size()Python 3.3で導入されました
villapx

最初はシャティルを試してみましたが、最初の試みでうまくいきました。Python 3.6以降を使用しています。
Dan

os.get_terminal_size(0)stdinにパイプすると、を使用するとクラッシュします。試してみる:echo x | python3 -c 'import os; print(os.get_terminal_size(0))'
ehabkost


6

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

  • getTerminalSize する必要があります import os
  • なにenv?のように見えますos.environ

また、なぜ切り替えるlinescols返す前に?場合TIOCGWINSZsttyの両方が言うlinesそしてcols、私はそのように残して言います。これは、私が矛盾に気付く前に10分間混乱させました。

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)

私も迷っていましたenvが、確かenv = os.environに、受け入れられた答えからです。
sdaau 2013年

6

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

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

2

私はここから呼び出しを行う解決策を試していました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()

2

「祝福」を試してください

全く同じものを探していました。これは非常に使いやすく、端末での色付け、スタイル設定、配置のためのツールを提供します。必要なのは次のように簡単です。

from blessings import Terminal

t = Terminal()

w = t.width
h = t.height

Linuxの魅力のように動作します。(MacOSXとWindowsについてはわかりません)

ここからダウンロードしてドキュメントを作成

または、pipを使用してインストールできます。

pip install blessings

現在私は、現在維持されている「祝福」のフォーク(および拡張)である「祝福」を試してみると思います。
zezollo

1

@reannualの回答は適切に機能しますが、問題があります:os.popen は非推奨になりましたsubprocessモジュールはので、ここで使用していること@ reannualのコードのバージョンですが、代わりに使用する必要がありますsubprocess直接として直接列幅を与えることによって(質問に答えるにはint

import subprocess

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

OS X 10.9でテスト済み


1

Python 3.3以降を使用している場合は、組み込みをget_terminal_size()お勧めします。ただし、古いバージョンで立ち往生していて、これを行う単純なクロスプラットフォームの方法が必要な場合は、asciimaticsを使用できます。このパッケージは2.7までのバージョンのPythonをサポートし、上記のオプションと同様のオプションを使用して、現在のターミナル/コンソールサイズを取得します。

Screenクラスを作成し、dimensionsプロパティを使用して高さと幅を取得するだけです。これは、Linux、OSX、Windowsで動作することが証明されています。

ああ、ここで完全に開示します:私は著者です。これを機能させるのに問題がある場合は、新しい問題を自由に開いてください。


0

これは、LinuxとSolarisの互換性があるバージョンです。以下からの投稿とcommmentsに基づきmadchine。サブプロセスモジュールが必要です。

def termsize():
    shlex、サブプロセス、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( 'rows')、m.group( 'columns')を返します
    OSErrorを発生させる( '不正な応答:%s'%(出力))
>>> termsize()
( '40'、 '100')
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.