파이썬에서 리눅스 콘솔 창 너비를 얻는 방법


264

파이썬에서 콘솔의 너비를 프로그래밍 방식으로 결정하는 방법이 있습니까? 나는 창의 픽셀 너비가 아니라 줄 바꿈없이 한 줄에 맞는 문자 수를 의미합니다.

편집하다

Linux에서 작동하는 솔루션을 찾고


"열에 의존하는"인쇄 메커니즘이있는보다 광범위한 솔루션을 보려면이 답변을보십시오. stackoverflow.com/questions/44129613/…
리카르도 페트라 글 리아

답변:


262
import os
rows, columns = os.popen('stty size', 'r').read().split()

파이썬 메일 링리스트의 스레드에 따라 'stty size'명령을 사용합니다 . 리눅스에서는 합리적입니다. 'stty size'명령을 파일로 열고 파일에서 읽은 다음 간단한 문자열 분할을 사용하여 좌표를 구분합니다.

os.environ [ "COLUMNS"] 값과 달리 (표준 쉘로 bash를 사용하더라도 액세스 할 수 없음) 데이터도 최신 상태이지만 os.environ [ "COLUMNS"] 값은 파이썬 인터프리터가 시작된 시간에만 유효합니다 (그 이후로 사용자가 창 크기를 조정했다고 가정하십시오).

(python 3.3 이상 에서이 작업을 수행하는 방법에 대한 @GringoSuave의 답변 참조)


1
"size"대신 "-a"를 전달하면 Solaris에서도 작동하도록 할 수 있습니다. 세미콜론으로 구분 된 출력에 "행 = Y; 열 = X"가 있습니다.
Joseph Garvin

5
COLUMNS는 Bash에서 기본적으로 내보내지지 않으므로 os.environ [ "COLUMNS"]이 작동하지 않습니다.
Kjell Andreassen

38
rows, columns = subprocess.check_output(['stty', 'size']).split()조금 짧은 플러스 서브 프로세스는 미래입니다
cdosborn

7
stty는 PIPE와 함께 작동 할 수 없으므로 tput이 stty보다 낫습니다.
liuyang1

5
rows, columns = subprocess.check_output(['stty', 'size']).decode().split()py2 / 3 호환성을위한 유니 코드 문자열을 원한다면
Bryce Guinta

264

왜 모듈에 있는지 shutil모르지만 파이썬 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

5
@osirisgothra 많은 호스팅 제공 업체들이 아직 python3을 지원하지 않기 때문에 우리 중 일부는 백엔드 개발을 위해 python2를 사용해야합니다. 터미널 크기를 얻는 것과는 아무 관련이 없지만 ...
whitebeard

4
@osirisgothra 포팅에 너무 많은 작업이 필요한 Python 2 코드가 많기 때문입니다. 또한 Pypy는 여전히 Python 3 지원이 다소 부족합니다.
안티몬

2
@whitebeard 구독자가 VPS에 Python 3을 설치할 수없는 이유가 있습니까? 또는 2016 년에도 관리자가 Python 3을 설치하지 않으려는 공유 호스팅을 계속 사용하고 있습니까? 예를 들어 WebFaction 공유 호스팅이 python3.5설치되었습니다.
데미안 예릭

2
표준 입력이 파일에서 리디렉션 될 때도 작동하는 솔루션의 경우 +1! 다른 솔루션을 사용하면 Inappropriate ioctl for device오류 / 경고 가 발생하거나 정의 된 폴백 값 80을
얻었습니다

65

사용하다

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

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

편집 : 아, 죄송합니다. 그것은 파이썬 표준 라이브러리가 아닙니다. 여기서 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에서 작동하는 솔루션을 찾고 있습니다. 아마도 태그에서 분명하지 않았으므로 그에 따라 질문을 편집 할 것입니다.
Sergey Golovchenko

2
사용중인이 "콘솔"모듈은 표준 파이썬 라이브러리에 없으므로 소스 코드 또는 최소한 링크를 제공해야합니다.
nosklo

유감입니다 사실, 나는 그 모듈을 몰랐다. 가져 오기 콘솔을 시도했지만 작동했는데 console. <tab> <tab> 및 getTerminalSize ()가 표시되었습니다. 대신이 어디 이미 대답을 게시에서 나는 단순 너무 운이 좋았다 때문에 보는 g
요하네스 와이즈

다른 "콘솔"모듈을보고있을 수 있습니다. 가지고있는 모듈에 대한 링크를 제공해 주시겠습니까?
Sergey Golovchenko

4
아, 그리고 코드를 쌓아 두지 말고 "cr"은 튜플이 (콜, 행)임을 암시하기 때문에 혼란스러운 이름입니다. 실제로는 그 반대입니다.
Paul Du Bois 5

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 일 수 있으므로 '1'을 파일 디스크립터 (ioctl의 첫 번째 인수)로 사용해야합니다.
mic_e

1
아마도 0은fcntl.ioctl(sys.stdin.fileno(), ...
raylu

4
사용자는 용어 폭 얻기 위해 단지 일어나고 깜짝 하위 프로세스가 아니라고 행복 할 것이다 -이 최고의 답변입니다
zzzeek

4
이것은 실제로 가장 깨끗한 대답입니다. 그래도 stdout또는 stderr대신에 사용해야한다고 생각합니다 stdin. stdin파이프 일 수도 있습니다. 과 같은 줄을 추가 할 수도 있습니다 if not os.isatty(0): return float("inf").
mic_e

이것은 어떻게 든 기능이없는 크롬 북 터미널에서 작동합니다. +1
HyperNeutrino

39

나는 주변에서 검색하고 창문에 대한 해결책을 찾았습니다.

http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/

여기에 리눅스 솔루션이 있습니다.

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에서도 작동합니다. 감사!
Steve V.

30

다음 중 하나입니다.

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

shutil기능은 os약간의 오류를 포착하고 폴백을 설정 하는 래퍼입니다 . 그러나 한 가지 큰 경고가 있습니다 . , 이것은 꽤 큰 거래입니다.
배관시 터미널 크기를 얻으려면 os.get_terminal_size(0)대신 사용하십시오.

첫 번째 주장 0 는 기본 stdout 대신 stdin 파일 디스크립터를 사용해야 함을 나타내는 입니다. stdin이 파이프 될 때 자체가 분리 되어이 경우 오류가 발생하기 때문에 stdin을 사용하려고합니다.

나는 stdin 인수 대신 stdout을 사용하는 것이 언제 의미가 있는지 알아 내려고 왜 이것이 기본값인지 알지 못했습니다.


3
os.get_terminal_size()Python 3.3에서 소개되었습니다
villapx 2014 년

나는 처음에 shutil을 시도했고 그것은 첫 번째 시도에서 효과가있었습니다. 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, 출력을 파이프 할 때 그 오류가 발생하지 않았습니다. 시험 제외에서 제대로 잡히고 있다고 확신합니다.

파스칼, "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

6

이 스크립트를 호출 할 때 제어 터미널이 없으면 많은 Python 2 구현이 실패합니다. sys.stdout.isatty ()를 검사하여 이것이 실제로 터미널인지 확인할 수 있지만 많은 경우를 제외시킬 것이므로 터미널 크기를 알아내는 가장 파이썬적인 방법은 내장 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

리눅스에서 매력처럼 작동합니다. (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()권장 사항을 이미 권장합니다. 그러나 이전 버전을 사용하고 있고이를 수행하는 간단한 크로스 플랫폼 방식을 원할 경우 비산 법을 사용할 수 있습니다 . 이 패키지는 2.7로 돌아가는 Python 버전을 지원하며 위에 제시된 것과 유사한 옵션을 사용하여 현재 터미널 / 콘솔 크기를 얻습니다.

Screen클래스를 구성 하고 dimensions속성을 사용 하여 높이와 너비를 얻으십시오. 이것은 Linux, OSX 및 Windows에서 작동하는 것으로 입증되었습니다.

아-그리고 여기에 전체 공개 : 나는 저자이므로,이 문제를 해결하는 데 문제가 있으면 언제든지 새로운 문제를여십시오.


0

다음은 Linux 및 Solaris 호환 버전이어야합니다. 에서 게시물과 commments을 바탕으로 madchine . 서브 프로세스 모듈이 필요합니다.

데프 termize () :
    shlex, 하위 프로세스 가져 오기, 다시 가져 오기
    출력 = subprocess.check_output (shlex.split ( '/ bin / stty -a'))
    m = re.search ( 'rows \ D + (? P \ d +); columns \ D + (? P \ d +);', 출력)
    m 인 경우 :
        m.group ( 'rows'), m.group ( 'columns') 반환
    OSError 발생 ( '잘못된 응답 : % s'% (출력))
>>> termsize ()
( '40', '100')
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.