Pythonでコンソールの幅をプログラムで決定する方法はありますか? ウィンドウのピクセル幅ではなく、折り返しなしで 1 行に収まる文字数を意味します。
編集
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()
Pythonメーリングリストのスレッドによると、 Linuxではかなり普遍的な「stty size」コマンドを使用します。「stty size」コマンドをファイルとして開き、そこから「読み取り」、単純な文字列分割を使用して座標を分離します。
os.environ["COLUMNS"] の値 (標準シェルとして bash を使用しているにもかかわらずアクセスできない) とは異なり、データも最新のものになりますが、os.environ["COLUMNS"] は値は、Python インタープリターの起動時にのみ有効です (それ以降、ユーザーがウィンドウのサイズを変更したとします)。
(python 3.3+でこれを行う方法については、@GringoSuaveの回答を参照してください)
使用する
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])
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 には、ピクセルの幅と高さを含める必要がありますが、含めないでください。
私は周りを検索し、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 2 実装の多くは、このスクリプトを呼び出すときに制御端末がないと失敗します。sys.stdout.isatty() をチェックして、これが実際に端末であるかどうかを判断できますが、それでは多くのケースが除外されるため、端末のサイズを把握する最も Pythonic な方法は、組み込みの curses パッケージを使用することだと思います。
import curses
w = curses.initscr()
height, width = w.getmaxyx()
そのコードにはいくつか問題があるようです、ヨハネス:
getTerminalSize
する必要があるimport os
env
ですか?のように見えos.environ
ます。また、なぜ戻る前に切り替えるlines
のですか?と両方が言うcols
なら、そのままにしておくと言います。これは、矛盾に気付く前に 10 分間混乱しました。TIOCGWINSZ
stty
lines
cols
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)
私はここから呼び出すソリューションを試していました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()
@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 でテスト済み
これは、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')