これは
qiita.com
初老丸 Advent Calendar 2017 9 日目の記事になる予定です.
tl;dr
Python スクリプト内で以下のように Print() を利用して ‘foo’ を標準出力させつつ, tee コマンドを使ってファイルにも書き出した際に学んだことのメモ.
import time while True: print('foo') time.sleep(3)
あれっ??
以下のように実行してファイルにも ‘foo’ を書き込みたかったんですが…
$ cat foo.py import time while True: print('foo') time.sleep(3) $ python foo.py | tee -a foo.txt ... 何も出力されないし...
これは困った, 困った, こまどり姉妹。
Python のヘルプを見ると…
$ python --version Python 2.7.13 $ python --help usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ... Options and arguments (and corresponding environment variables): -B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x ... 略 ... -u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x see man page for details on internal buffering relating to '-u' ... 略 ... PYTHONHASHSEED: if this variable is set to 'random', the effect is the same as specifying the -R option: a random value is used to seed the hashes of str, bytes and datetime objects. It can also be set to an integer in the range [0,4294967295] to get hash values with a predictable seed.
ふむふむ…man してみると以下のように出力されました.
$ man python2.7 ... 略 ... -u Force stdin, stdout and stderr to be totally unbuffered. On systems where it matters, also put stdin, stdout and stderr in binary mode. Note that there is internal buffering in xreadlines(), readlines() and file-object iterators ("for line in sys.stdin") which is not influenced by this option. To work around this, you will want to use "sys.stdin.readline()" inside a "while 1:" loop. ... 略 ...
-u
オプションは stdin, stdout, stderr バッファリングさせない為に利用するオプションということが解りました. デフォルトで Python は標準出力が改行されるタイミングでバッファがフラッシュされ, パイプで別のプロセスで処理させる場合にはバッファリングするとのこと.(参考)
以下のように -u
オプションを付与して実行するだけで, バッファリングが無効になり, 冒頭のスクリプトと tee コマンドを併用して標準出力とファイル出力を一緒に行うことが出来ました.
$ $ python -u foo.py | tee -a foo.log foo foo foo
One more thing
-u
オプションを付与する以外にも, sys モジュールの sys.stdout.flush() を利用してバッファをフラッシュすることで同様に出力を得ることが出来ました.
import time import sys while True: print('foo') sys.stdout.flush() time.sleep(3)
以下のように出力されました.
$ cat foo2.py import time import sys while True: print('foo') sys.stdout.flush() time.sleep(3) $ python foo2.py | tee -a foo2.log foo foo foo ^CTraceback (most recent call last): File "foo2.py", line 7, in <module> time.sleep(3) KeyboardInterrupt $ cat foo2.log foo foo foo
以上
メモでした.