

pythonの `subprocess.Popen`
で子プロセスのstdoutとstderrの内容を加工した上で、親のstdout、stderrにそれぞれリアルタイムに、且つ順番通りに出力したいです。  
例えば、以下の `hoge.sh` を `実行例` のように実行したいです。

hoge.sh

[code]

    echo yes1
    echo no1  >&2
    echo yes21
    echo yes22
    echo no2  >&2
    
[/code]

fuga.py:

[code]

    import subprocess as sp
    p = sp.Popen(['bash', 'hoge.sh'], stdout=sp.PIPE, stderr=sp.PIPE, ...)
    
    ~~  p.stdoutは先頭に"out:"を、p.stderrは"err:"をつけて出力 ~~
    
    p.wait()
    
[/code]

実行例:

[code]

    $ python fuga.py                ※加工されたstdout stderr が順番通り出力される
    out: yes1
    err: no1
    out: yes21
    out: yes22
    err: no2
    $ python fuga.py > /dev/null    ※加工されたstderr のみ出力される
    err: no1
    err: no2
    
[/code]

* * *

ネットで見つけた以下のコードが今の所もっとも目的に近いのですが、こちらのコードではstdoutとstderrの順番が保証されません。

[code]

    #!/usr/bin/python3
    import subprocess
    import sys
    from subprocess import PIPE
    from threading import Thread
    
    
    def read_stream(in_file, out_file):
        for line in in_file:
            print(line.strip(), file=out_file, flush=True)
    
    p = subprocess.Popen("./test_stream.py", stdin=sys.stdin, stdout=PIPE, stderr=PIPE, universal_newlines=True)
    Thread(target=read_stream, args=(p.stdout, sys.stdout)).start()
    Thread(target=read_stream, args=(p.stderr, sys.stderr)).start()
    
[/code]

出力結果: （stdoutとstderrの順番が入れ替わることがある）

[code]

    out: yes1
    err: no1
    out: yes21
    err: no2
    out: yes22
    
[/code]

* * *

お力添えのほど何卒よろしくお願いします。


CC BY-SA 4.0
2019-11-15T06:20:20.623
60539
2020-05-17T19:48:53.023
2020-05-17T19:48:53.023
19110
28998
question
python python3 linux posix python-multiprocessing
subprocess.Popenのstdoutとstderrをリアルタイムに取得する


> stdoutとstderrの順番が入れ替わることがある

アプリ(bash) の 入力、出力が バッファリングされている可能性があって  
その バッファを アプリ側が 明示的に flush するような 起動オプションがないか調べる  
<https://gist.github.com/riywo/874011>

bash 自体に そのようなオプションはなさそうなので、  
linux の標準出力のバッファサイズを小さくする方法

[code]

    stdbuf -i0 -o0 -e0 <command>
    
[/code]

<https://stackoverflow.com/questions/36847897/in-bash-how-can-i-force-a-flush-
of-an-incomplete-line-printed-to-the-terminal>

を実行してみる。

あとは read_stream の中で 文字列処理を複数スレッドで行うと思うので  
この時に順番が入れ替わる可能性があるので、それは アプリ側で対策する。

等が考えられます。

試してないので違っているかもしれません。  
参考までに・・。


CC BY-SA 4.0
2019-11-15T06:57:33.610
60542
2019-11-15T06:57:33.610
18851
60539
answer