Python stdout을 즉시 파일로 작성


51

Python 스크립트에서 텍스트 파일 ( python script.py > log) 로 stdout을 쓰려고하면 명령이 시작될 때 텍스트 파일이 작성되지만 실제 내용은 Python 스크립트가 완료 될 때까지 작성되지 않습니다. 예를 들면 다음과 같습니다.

script.py :

import time
for i in range(10):
    print('bla')
    time.sleep(5)

로 호출하면 5 초마다 stdout으로 인쇄 python script.py되지만 호출 python script.py > log하면 스크립트가 완료 될 때까지 로그 파일의 크기가 0으로 유지됩니다. 스크립트의 진행 상황을 따를 수 있도록 로그 파일에 직접 쓸 수 tail있습니까 (예 :) ?

편집 그것은 python -u script.py트릭 을 수행하는 것으로 나타났습니다 . 나는 stdout의 버퍼링에 대해 몰랐습니다.


1
@ jezmck, 나는 잘못된 질문을 이해할 수있었습니다.
zyxue

답변:


64

이는 일반적으로 프로세스 STDOUT이 터미널 이외의 다른 경로로 경로 재 지정 될 때 출력이 일부 OS 특정 크기 버퍼 (대부분의 경우 4k 또는 8k)로 버퍼링되기 때문에 발생합니다. 반대로, 터미널로 출력 할 때 STDOUT은 라인 버퍼링되거나 전혀 버퍼링되지 않으므로 \n각 문자 다음 또는 각 문자에 대한 출력을 볼 수 있습니다 .

일반적으로 stdbuf유틸리티를 사용하여 STDOUT 버퍼링을 변경할 수 있습니다 .

stdbuf -oL python script.py > log

이제이면 tail -F log생성되는 즉시 각 라인 출력을 볼 수 있습니다.


또는 각 인쇄 후 출력 스트림의 명시 적 플러싱이 동일해야합니다. sys.stdout.flush()파이썬에서 이것을 달성 해야하는 것처럼 보입니다 . Python 3.3 이상을 사용하는 경우 print함수에는 다음과 같은 flush키워드 도 있습니다 print('hello', flush=True).


8
감사합니다. 버퍼링에 대해 몰랐습니다! 그것을 알면서, 구글 python -u script.py은 그 트릭 을 수행 한다고 나에게 빨리 말했다 . 편집 한 번에 너무 많은 답변, 버퍼링 방향으로 나를 지적했기 때문에 나는 당신의 것을 받아 들였습니다.
Bart

1
@julbra Cool, 그렇습니다. 파이썬에도 그 옵션이 있다는 것을 몰랐습니다. 일부 명령 줄 프로그램에도 유사한 옵션이 있습니다 (예 : --line-bufferedfor grep). stdbuf그렇지 않은 것을 다루는 일반적인 catchall 유틸리티입니다.
Digital Trauma

@DigitalTrauma : stdbuf -o0 python script.py > log이런 종류의 결정된 환경에서 버퍼링을 전혀 사용하지 않는 것이 좋 습니까?
heemayl

@heemayl -oL은 타협입니다. 일반적으로 더 큰 버퍼는 다른 곳으로 리디렉션 할 때 더 나은 성능을 제공합니다 (시스템 호출이 적고 I / O 작업이 적음). 그러나 출력 할 때 각 문자를 볼 필요가있는 경우에는 그렇습니다 -o0.
디지털 외상

@Paul 답변 사이에 내용을 붙여 넣거나 내용을 제공 한 원저자를 언급하지 마십시오.
Bakuriu

44

이것은 일을해야합니다 :

import time, sys
for i in range(10):
    print('bla')
    sys.stdout.flush()
    time.sleep(5)

파이썬이 stdout기본적으로 sys.stdout.flush()버퍼링하므로 버퍼를 플러시하는 데 사용 했습니다.

또 다른 해결책은의 -u(언 버퍼링 된) 스위치 를 사용하는 것 입니다 python. 따라서 다음도 수행됩니다.

python -u script.py >> log

11

버퍼되지 않은 출력에 파이썬 자체 옵션을 사용하는 주제에 대한 변형 #!/usr/bin/python -u은 첫 번째 줄로 사용하는 것 입니다.

#!/usr/bin/env python그 여분의 인수거야하지 작업, 그래서 대안으로, 하나는 실행할 수 PYTHONUNBUFFERED=1 ./my_scriipt.py > output.txt또는 두 단계를 수행합니다

$ export PYTHONUNBUFFERED=1
$ ./myscript.py

10

당신은 통과해야 flush=True받는 print기능 :

import time

for i in range(10):
    print('bla', flush=True)
    time.sleep(5)

설명서에 따르면 기본적으로 print플러싱에 대해서는 아무것도 적용하지 않습니다.

출력이 버퍼링되는지 여부는 일반적으로 파일에 의해 결정되지만 flush키워드 인수가 true이면 스트림이 강제로 플러시됩니다.

그리고 sysstrem에 대한 문서 는 다음과 같이 말합니다.

대화식 일 때 표준 스트림은 라인 버퍼링됩니다. 그렇지 않으면 일반 텍스트 파일처럼 차단됩니다. -u명령 행 옵션 으로이 값을 대체 할 수 있습니다 .


고대 버전의 파이썬에 갇혀 있다면 스트림 의 flush메소드 를 호출 해야 sys.stdout합니다.

import sys
import time

for i in range(10):
    print('bla')
    sys.stdout.flush()
    time.sleep(5)

1
flush = True 인수는 Python 3.4.2에서 잘 작동합니다. 실제로 고대 (..) Python 2.7.9에서 작동하지 않습니다.
Bart

이 답변은 DigitalTrauma10 시간 전에 말한 것과 같은 것을 제안합니다 . 같은 게시물을 다시 게시하지 말고 자신의 게시물을 공표해야합니다.
dotancohen

4
사실에 대한 부분 @dotancohen print(flush=True)그 대답에 추가 된 타사 저자에 의해 내. 내 답변에서 내용을 추출하여 크레딧없이 다른 내용을 넣는 것은 나쁜 맛입니다. 나는 내 대답을 추가하기로 결정 전적으로 아무런 답변을 영업 이익은 파이썬의 최신 버전에서 원하는 것을 달성하는 간단한 방법에 대한 언급을 제공하지 않기 때문에, 난 그냥 완전성에 대해 "옛날 방식"을 추가했다. 다음에 주석 및 / 또는 다운 보팅하기 전에 개정 내역을 확인하십시오.
Bakuriu

@Bakuriu : 죄송합니다! 이것은 downvoting 할 때 항상 이유를 게시 해야하는 좋은 이유를 보여줍니다 . 다운 보트를 업 보트로 변경할 수 있도록 게시물을 약간 편집 해 주시겠습니까? 감사합니다!
dotancohen

__future__가져 오기 를 수행하면 Python 2.7에서 작동 from __future__ import print_function합니다. 그러나 그렇습니다. 그것은 Python 3과의 호환성만을위한 것입니다
Sergiy Kolodyazhnyy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.