如何在 Python 中获取 Linux 控制台窗口宽度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/566746/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get Linux console window width in Python
提问by Sergey Golovchenko
Is there a way in python to programmatically determine the width of the console? I mean the number of characters that fits in one line without wrapping, not the pixel width of the window.
python中有没有办法以编程方式确定控制台的宽度?我的意思是一行中没有换行的字符数,而不是窗口的像素宽度。
Edit
编辑
Looking for a solution that works on Linux
寻找适用于 Linux 的解决方案
采纳答案by brokkr
import os
rows, columns = os.popen('stty size', 'r').read().split()
uses the 'stty size' command which according to a thread on the python mailing listis reasonably universal on linux. It opens the 'stty size' command as a file, 'reads' from it, and uses a simple string split to separate the coordinates.
使用 'stty size' 命令,根据python 邮件列表上的一个线程,该命令在 linux 上相当普遍。它将“stty size”命令作为文件打开,从中“读取”,并使用简单的字符串拆分来分隔坐标。
Unlike the os.environ["COLUMNS"] value (which I can't access in spite of using bash as my standard shell) the data will also be up-to-date whereas I believe the os.environ["COLUMNS"] value would only be valid for the time of the launch of the python interpreter (suppose the user resized the window since then).
与 os.environ["COLUMNS"] 值(尽管使用 bash 作为我的标准外壳我无法访问)不同,数据也将是最新的,而我相信 os.environ["COLUMNS"] value 仅在 python 解释器启动时有效(假设用户从那时起调整了窗口大小)。
(See answer by @GringoSuave on how to do this on python 3.3+)
(请参阅@GringoSuave 关于如何在 python 3.3+ 上执行此操作的答案)
回答by Johannes Weiss
use
用
import console
(width, height) = console.getTerminalSize()
print "Your terminal's width is: %d" % width
EDIT: oh, I'm sorry. That's not a python standard lib one, here's the source of console.py (I don't know where it's from).
编辑:哦,对不起。那不是python标准库,这是console.py的来源(我不知道它来自哪里)。
The module seems to work like that: It checks if termcap
is available, when yes. It uses that; if no it checks whether the terminal supports a special ioctl
call and that does not work, too, it checks for the environment variables some shells export for that.
This will probably work on UNIX only.
该模块似乎是这样工作的:它检查是否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])
回答by pascal
Code above didn't return correct result on my linux because winsize-struct has 4 unsigned shorts, not 2 signed shorts:
上面的代码在我的 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 and hp should contain pixel width and height, but don't.
hp 和 hp 应该包含像素宽度和高度,但不要。
回答by thejoshwolfe
It looks like there are some problems with that code, Johannes:
看起来那个代码有一些问题,约翰内斯:
getTerminalSize
needs toimport os
- what is
env
? looks likeos.environ
.
getTerminalSize
需要import os
- 什么是
env
?看起来像os.environ
。
Also, why switch lines
and cols
before returning? If TIOCGWINSZ
and stty
both say lines
then cols
, I say leave it that way. This confused me for a good 10 minutes before I noticed the inconsistency.
另外,为什么在返回之前切换lines
和cols
?如果TIOCGWINSZ
和stty
两者都说lines
then cols
,我说就这样吧。在我注意到不一致之前,这让我困惑了 10 分钟。
Sridhar, I didn't get that error when I piped output. I'm pretty sure it's being caught properly in the try-except.
Sridhar,当我通过管道输出时,我没有收到那个错误。我很确定它在 try-except 中被正确捕获。
pascal, "HHHH"
doesn't work on my machine, but "hh"
does. I had trouble finding documentation for that function. It looks like it's platform dependent.
pascal,"HHHH"
在我的机器上"hh"
不起作用,但是可以。我无法找到该功能的文档。看起来它依赖于平台。
chochem, incorporated.
chochem, 合并
Here's my version:
这是我的版本:
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)
回答by Derrick Petzold
Here is an version that should be Linux and Solaris compatible. Based on the posts and commments from madchine. Requires the subprocess module.
这是一个应该与 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')
回答by Harco Kuppens
I searched around and found a solution for windows at :
我四处搜索并在以下位置找到了适用于 Windows 的解决方案:
http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/
http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/
and a solution for linux here.
以及这里的 linux 解决方案。
So here is a version which works both on linux, os x and windows/cygwin :
所以这里有一个适用于 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
回答by Gringo Suave
Not sure why it is in the module shutil
, but it landed there in Python 3.3, Querying the size of the output terminal:
不知道为什么它在模块中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
A low-level implementation is in the os module. Also works in Windows.
os 模块中有一个低级实现。也适用于 Windows。
A backport is now available for Python 3.2 and below:
现在可用于 Python 3.2 及以下版本的反向移植:
回答by Bob Enohp
Starting at Python 3.3 it is straight forward: https://docs.python.org/3/library/os.html#querying-the-size-of-a-terminal
从 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
回答by rickcnagy
@reannual's answer works well, but there's an issue with it: os.popen
is now deprecated. The subprocess
module should be used instead, so here's a version of @reannual's code that uses subprocess
and directly answers the question (by giving the column width directly as an int
:
@reannual 的回答很有效,但它有一个问题:os.popen
现在已弃用。subprocess
应该使用该模块,所以这里是使用subprocess
并直接回答问题的@reannual 代码的一个版本(通过将列宽直接作为一个int
:
import subprocess
columns = int(subprocess.check_output(['stty', 'size']).split()[1])
Tested on OS X 10.9
在 OS X 10.9 上测试
回答by Marc Liyanage
I was trying the solution from here that calls out to stty size
:
我正在尝试从这里调用的解决方案stty size
:
columns = int(subprocess.check_output(['stty', 'size']).split()[1])
However this failed for me because I was working on a script that expects redirected input on stdin, and stty
would complain that "stdin isn't a terminal" in that case.
但是,这对我来说失败了,因为我正在编写一个脚本,该脚本期望在 stdin 上重定向输入,并且stty
在这种情况下会抱怨“stdin 不是终端”。
I was able to make it work like this:
我能够让它像这样工作:
with open('/dev/tty') as tty:
height, width = subprocess.check_output(['stty', 'size'], stdin=tty).split()