Vraag Python Popen: schrijf gelijktijdig naar stdout EN log-bestand


Ik gebruik Popen om een ​​shellscript te bellen dat voortdurend zijn stdout en stderr naar een logbestand schrijft. Is er een manier om het logbestand tegelijkertijd (naar het scherm) tegelijk uit te voeren, of anders het shell-script tegelijkertijd naar het logbestand en naar stdout te schrijven?

Ik wil in principe zoiets doen in Python:

cat file 2>&1 | tee -a logfile #"cat file" will be replaced with some script

Nogmaals, deze pijpen stderr / stdout samen naar tee, die het zowel naar stdout als mijn logbestand schrijft.

Ik weet hoe ik stdout en stderr naar een logbestand in Python moet schrijven. Waar ik vast zit is hoe ik deze terug naar het scherm dupliceer:

subprocess.Popen("cat file", shell=True, stdout=logfile, stderr=logfile)

Natuurlijk kan ik zoiets als dit doen, maar is er een manier om dit te doen zonder tee en shell file descriptor redirection ?:

subprocess.Popen("cat file 2>&1 | tee -a logfile", shell=True)

28
2018-03-20 21:37


oorsprong


antwoorden:


U kunt een pijp gebruiken om de gegevens van de stdout van het programma te lezen en deze naar alle gewenste plaatsen te schrijven:

import sys
import subprocess

logfile = open('logfile', 'w')
proc=subprocess.Popen(['cat', 'file'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
    sys.stdout.write(line)
    logfile.write(line)
proc.wait()

BIJWERKEN

In python 3, de universal_newlines parameter bepaalt hoe leidingen worden gebruikt. Als False, pijp leest terug bytes objecten en moet mogelijk worden gedecodeerd (bijv. line.decode('utf-8')) om een ​​string te krijgen. Als True, Python decodeert voor jou

Gewijzigd in versie 3.3: Wanneer universal_newlines True is, gebruikt de klasse de codering locale.getpreferredencoding (False) in plaats van locale.getpreferredencoding (). Zie de klasse io.TextIOWrapper voor meer informatie over deze wijziging.


29
2018-03-20 21:46



Om te emuleren: subprocess.call("command 2>&1 | tee -a logfile", shell=True) zonder de tee opdracht:

#!/usr/bin/env python2
from subprocess import Popen, PIPE, STDOUT

p = Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1)
with p.stdout, open('logfile', 'ab') as file:
    for line in iter(p.stdout.readline, b''):
        print line,  #NOTE: the comma prevents duplicate newlines (softspace hack)
        file.write(line)
p.wait()

Zie de koppelingen in om mogelijke bufferproblemen op te lossen (als de uitvoer is vertraagd) Python: lees streamingingang van subproces.communicate ().

Hier is de Python 3-versie:

#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE, STDOUT

with Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1) as p, \
     open('logfile', 'ab') as file:
    for line in p.stdout: # b'\n'-separated lines
        sys.stdout.buffer.write(line) # pass bytes as is
        file.write(line)

6
2018-01-05 05:22