read subprocess stdout line by line

后端 未结 9 2060
一个人的身影
一个人的身影 2020-11-22 02:15

My python script uses subprocess to call a linux utility that is very noisy. I want to store all of the output to a log file and show some of it to the user. I thought the

相关标签:
9条回答
  • 2020-11-22 02:37

    I tried this with python3 and it worked, source

    def output_reader(proc):
        for line in iter(proc.stdout.readline, b''):
            print('got line: {0}'.format(line.decode('utf-8')), end='')
    
    
    def main():
        proc = subprocess.Popen(['python', 'fake_utility.py'],
                                stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT)
    
        t = threading.Thread(target=output_reader, args=(proc,))
        t.start()
    
        try:
            time.sleep(0.2)
            import time
            i = 0
    
            while True:
            print (hex(i)*512)
            i += 1
            time.sleep(0.5)
        finally:
            proc.terminate()
            try:
                proc.wait(timeout=0.2)
                print('== subprocess exited with rc =', proc.returncode)
            except subprocess.TimeoutExpired:
                print('subprocess did not terminate in time')
        t.join()
    
    0 讨论(0)
  • 2020-11-22 02:40

    Bit late to the party, but was surprised not to see what I think is the simplest solution here:

    import io
    import subprocess
    
    proc = subprocess.Popen(["prog", "arg"], stdout=subprocess.PIPE)
    for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):  # or another encoding
        # do something with line
    

    (This requires Python 3.)

    0 讨论(0)
  • 2020-11-22 02:42

    You want to pass these extra parameters to subprocess.Popen:

    bufsize=1, universal_newlines=True
    

    Then you can iterate as in your example. (Tested with Python 3.5)

    0 讨论(0)
  • 2020-11-22 02:43

    It's been a long time since I last worked with Python, but I think the problem is with the statement for line in proc.stdout, which reads the entire input before iterating over it. The solution is to use readline() instead:

    #filters output
    import subprocess
    proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
    while True:
      line = proc.stdout.readline()
      if not line:
        break
      #the real code does filtering here
      print "test:", line.rstrip()
    

    Of course you still have to deal with the subprocess' buffering.

    Note: according to the documentation the solution with an iterator should be equivalent to using readline(), except for the read-ahead buffer, but (or exactly because of this) the proposed change did produce different results for me (Python 2.5 on Windows XP).

    0 讨论(0)
  • 2020-11-22 02:45

    The following modification of Rômulo's answer works for me on Python 2 and 3 (2.7.12 and 3.6.1):

    import os
    import subprocess
    
    process = subprocess.Popen(command, stdout=subprocess.PIPE)
    while True:
      line = process.stdout.readline()
      if line != '':
        os.write(1, line)
      else:
        break
    
    0 讨论(0)
  • 2020-11-22 02:47

    Dunno when this has been added to the subprocess module, but with Python 3 you should be fine with using proc.stdout.splitlines():

    for line in proc.stdout.splitlines():
       print "stdout:", line
    
    0 讨论(0)
提交回复
热议问题