Pythonスクリプトからテキストファイル()にstdoutを書き込もうとすると、python script.py > log
コマンドの起動時にテキストファイルが生成されますが、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
これは通常、プロセスのSTDOUTが端末以外の場所にリダイレクトされると、出力が一部のオペレーティングシステム固有のサイズ(多くの場合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)
答え2
これを行う必要があります。
import time, sys
for i in range(10):
print('bla')
sys.stdout.flush()
time.sleep(5)
stdout
Pythonバッファはデフォルトではバッファなので、sys.stdout.flush()
ここではフラッシュバッファを使用します。
-u
別の解決策は(バッファされていない)スイッチを使用することですpython
。したがって、以下も機能します。
python -u script.py >> log
答え3
Python自体のバッファリングされていない出力オプションを使用したテーマバリアントが#!/usr/bin/python -u
最初の行として使用されます。
この追加引数は効果がないため、次の2つのステップで実行または実行することを#!/usr/bin/env python
選択できます。PYTHONUNBUFFERED=1 ./my_scriipt.py > output.txt
$ export PYTHONUNBUFFERED=1
$ ./myscript.py
答え4
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)