web-dev-qa-db-ja.com

書き込みPython stdout to file即時

Pythonスクリプトからstdoutをテキストファイル(python script.py > log)に書き込もうとすると、コマンドの開始時にテキストファイルが作成されますが、実際のコンテンツは書き込まれませんPythonスクリプトが終了するまで。例:

script.py:

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

python script.pyで呼び出されると、5秒ごとにstdoutに出力されますが、python script.py > logを呼び出すと、スクリプトが完了するまでログファイルのサイズはゼロのままです。スクリプトの進行状況を追跡できるように、ログファイルに直接書き込むことは可能ですか(例:tail)。

[〜#〜] edit [〜#〜]python -u script.pyがトリックを実行することがわかりました。標準出力のバッファリングについては知りませんでした。

60
Bart

これは通常、プロセスSTDOUTが端末以外にリダイレクトされると、出力がOS固有のサイズのバッファー(多くの場合4kまたは8k)にバッファーされるために発生します。逆に、端末に出力する場合、STDOUTはラインバッファリングされるか、まったくバッファリングされないため、各_\n_または各文字の後に出力が表示されます。

通常、STDOUTバッファリングは stdbuf ユーティリティで変更できます。

_stdbuf -oL python script.py > log
_

ここで_tail -F log_を実行すると、生成された各行の出力がすぐに表示されます。


あるいは、各印刷後の出力ストリームの明示的なフラッシュは、同じことを達成する必要があります。 sys.stdout.flush() はPythonでこれを実現するようです。 Python 3.3以降を使用している場合、print関数にはこれを行うflushキーワードもあります:print('hello', flush=True)

70
Digital Trauma

これは仕事をするはずです:

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

Pythonはデフォルトでstdoutをバッファリングするため、ここではsys.stdout.flush()を使用してバッファをフラッシュしています。

別の解決策は、pythonの_-u_(unbuffered)スイッチを使用することです。したがって、以下も実行します。

_python -u script.py >> log
_
47
heemayl

バッファリングされていない出力にpython独自のオプションを使用するというテーマのバリエーションは、最初の行として#!/usr/bin/python -uを使用することです。

#!/usr/bin/env pythonを使用すると、その追加の引数は機能しないため、代わりにPYTHONUNBUFFERED=1 ./my_scriipt.py > output.txtを実行するか、2つのステップで実行できます。

$ export PYTHONUNBUFFERED=1
$ ./myscript.py
14

flush=Trueprint 関数に渡す必要があります。

import time

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

ドキュメントによると、デフォルトでは、printはフラッシュについて何も強制しません。

出力がバッファリングされるかどうかは通常ファイルによって決定されますが、flushキーワード引数がtrueの場合、ストリームは強制的にフラッシュされます。

そしてsysのstremsのドキュメントはこう言っています:

インタラクティブな場合、標準ストリームはラインバッファリングされます。それ以外の場合は、通常のテキストファイルと同様にブロックバッファリングされます。この値は、-uコマンドラインオプションで上書きできます。


pythonの古いバージョンで立ち往生している場合は、 flush メソッドを呼び出す必要があります sys.stdout ストリーム:

import sys
import time

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