[英]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
。 另外,為什么開關lines
和cols
返回前? 如果TIOCGWINSZ
和stty
都說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.