---
# System prepended metadata

title: Python の `-u` オプションを用いて stdout と stderr のバッファを行わないようにする

---

# Python の `-u` オプションを用いて stdout と stderr のバッファを行わないようにする

Python内で新しい子プロセスを立ち上げる時に、Pythonの `subprocess` モジュールを用いることで、子プロセスを良い感じに抽象化して扱うことができます。例えば以下のコードでは、Bashスクリプトを子プロセスで実行し、その子プロセスの標準出力を文字列として受け取っています。ここで注目して欲しいのは、`asyncio` を用いて、標準出力をインタラクティブに受け取れることです。1秒ごとに、インクリメントされた数値が表示されます。

```:python
cmd = 'for i in `seq 1 5`; do echo $i; sleep 1; done'
proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE)
async for data in proc.stdout:
    line = data.decode('ascii').rstrip()
    print(line)
```

![](https://i.imgur.com/zl0kpPy.gif)


ここで、BashではなくPythonの子プロセスを立ち上げて結果を受け取ってみようと考え、以下のコードを作成しました。
```:python
cmd = \
    'python -c "' + \
    'import time\n' + \
    'for i in range(5): print(i); time.sleep(1)"'
proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE)
async for data in proc.stdout:
    line = data.decode('ascii').rstrip()
    print(line)
```
![](https://i.imgur.com/gJdAUQU.gif)

いざこのプログラムを実行してみると、期待通りの結果が得られませんでした。最初に示したプログラムでは1秒毎に数値が表示されていましたが、上記プログラムを実行すると、最初5秒間は何も表示されず、5秒後に全ての結果が一気に表示されてしまいました。

色々試してみましたが、Pythonプログラムに変更を加えても、インタラクティブに結果を受け取ることはできませんでした。挙動を見る限り、どこかに文字列がバッファされているようだったので、もしや Python のランタイムが怪しいのではと思いググると、あっさり問題は解決しました。

PythonのCLIツールには、`-u` オプションというものがあります。`-u` オプションは、Pythonのランタイムに stdout と stderr のバッファをさせるかどうかを決めるオプションです。デフォルトでは、バッファをするようになっているため、このオプションをつけることでバッファをしないようにします。

`-u` オプションを追記した以下のプログラムでは、期待通りにインタラクティブな結果を得ることができました。よかった。

```:python
cmd = \
    'python -u -c "' + \
    'import time\n' + \
    'for i in range(5): print(i); time.sleep(1)"'
proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE)
async for data in proc.stdout:
    line = data.decode('ascii').rstrip()
    print(line)
```

![](https://i.imgur.com/uRO3sNw.gif)


今回は表面的な調査しかしていませんが、また時間があれば Python ランタイムでどのようにバッファが行われているのか、調査してみたいです。

## 参考文献
- [Python: significance of -u option? - stack overflow](https://stackoverflow.com/questions/14258500/python-significance-of-u-option)

## コード全文
```:python
import asyncio
import sys

async def run():
    cmd = \
        'python -u -c "' + \
        'import time\n' + \
        'for i in range(5): print(i); time.sleep(1)"'

    proc = await asyncio.create_subprocess_shell(
            cmd,
            stdout=asyncio.subprocess.PIPE)

    async for data in proc.stdout:
        line = data.decode('ascii').rstrip()
        print(line)

    await proc.wait()

asyncio.run(run())
```