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
がトリックを実行することがわかりました。標準出力のバッファリングについては知りませんでした。
これは通常、プロセス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)
。
これは仕事をするはずです:
_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
_
バッファリングされていない出力にpython独自のオプションを使用するというテーマのバリエーションは、最初の行として#!/usr/bin/python -u
を使用することです。
#!/usr/bin/env python
を使用すると、その追加の引数は機能しないため、代わりにPYTHONUNBUFFERED=1 ./my_scriipt.py > output.txt
を実行するか、2つのステップで実行できます。
$ export PYTHONUNBUFFERED=1
$ ./myscript.py
flush=True
を print
関数に渡す必要があります。
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)