Как копировать поведение мишени в Python при использовании подпроцесса?

Я ищу решение Python, которое позволит мне сохранять вывод команды в файле, не скрывая его от консоли.

К вашему сведению: я спрашиваю о мишени (как утилита командной строки Unix) а не функция с тем же именем от модуля межинструментов Python.

Подробнее

  • Решение Python (не вызов tee, это не доступно в соответствии с Windows),
  • Я не должен предоставлять вход stdin для названного процесса
  • Я не имею никакого контроля над названной программой. Все, что я знаю, - то, что это произведет что-то к stdout и stderr и возвратится с кодом выхода.
  • Работать при вызове внешних программ (подпроцесс)
  • Работать на обоих stderr и stdout
  • Способность дифференцироваться между stdout и stderr, потому что я могу хотеть отобразить только один из к консоли или я мог попытаться произвести stderr использование другого цвета - это означает это stderr = subprocess.STDOUT не будет работать.
  • Живой (прогрессивный) вывод - процесс может работать в течение долгого времени, и я не могу ожидать его для окончания.
  • Python 3 совместимый (важный) код

Ссылки

Вот некоторые неполные решения, которые я нашел до сих пор:

Схема http://blog.i18n.ro/wp-content/uploads/2010/06/Drawing_tee_py.png

Текущий код (вторая попытка)

#!/usr/bin/python
from __future__ import print_function

import sys, os, time, subprocess, io, threading
cmd = "python -E test_output.py"

from threading import Thread
class StreamThread ( Thread ):
    def __init__(self, buffer):
        Thread.__init__(self)
        self.buffer = buffer
    def run ( self ):
        while 1:
            line = self.buffer.readline()
            print(line,end="")
            sys.stdout.flush()
            if line == '':
                break

proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutThread = StreamThread(io.TextIOWrapper(proc.stdout))
stderrThread = StreamThread(io.TextIOWrapper(proc.stderr))
stdoutThread.start()
stderrThread.start()
proc.communicate()
stdoutThread.join()
stderrThread.join()

print("--done--")

#### test_output.py ####

#!/usr/bin/python
from __future__ import print_function
import sys, os, time

for i in range(0, 10):
    if i%2:
        print("stderr %s" % i, file=sys.stderr)
    else:
        print("stdout %s" % i, file=sys.stdout)
    time.sleep(0.1)

Реальный вывод

stderr 1
stdout 0
stderr 3
stdout 2
stderr 5
stdout 4
stderr 7
stdout 6
stderr 9
stdout 8
--done--

Ожидаемому выводу состоял в том, чтобы заказать строки. Комментарий, изменяя Popen для использования только одного КАНАЛА не позволяется, потому что в реальной жизни я захочу сделать разные вещи с stderr и stdout.

Также даже во втором случае я не смог получить в реальном времени как, на самом деле все результаты были получены когда законченный процесс. По умолчанию Popen не должен использовать буферы (bufsize=0).

63
задан 14 revs, 2 users 67% 17 April 2015 в 13:42
поделиться

4 ответа

Наконец, мне пришлось самому реализовать команду tee () на Python.

Вы можете получить его отсюда http://github.com/pycontribs/tendo/blob/master/tendo/tee.py

В настоящее время он позволяет делать такие вещи, как:

 tee("python --v") # works just like os.system()

 tee("python --v", "log.txt") # file names

 tee("python --v", file_handle)

 import logging
 tee("python --v", logging.info) # receive a method

единственное текущее ограничение состоит в том, что он не может различать stderr и stdout , что означает, что он объединит их оба.

13
ответ дан 4 July 2019 в 21:42
поделиться

Это прямой перенос tee на Python.

import sys
sinks = sys.argv[1:]
sinks = [open(sink, "w") for sink in sinks]
sinks.append(sys.stderr)
while True:
  input = sys.stdin.read(1024)
  if input:
    for sink in sinks:
      sink.write(input)
  else:
    break

Сейчас я работаю на Linux, но это должно работать на большинстве платформ.


Теперь о части subprocess, я не знаю, как вы хотите "подключить" stdin подпроцесса, stdout и stderr к вашим stdin, stdout, stderr и поглотителям файлов, но я знаю, что вы можете это сделать:

import subprocess
callee = subprocess.Popen( ["python", "-i"],
                           stdin = subprocess.PIPE,
                           stdout = subprocess.PIPE,
                           stderr = subprocess.PIPE
                         )

Теперь вы можете получить доступ к callee. stdin, callee.stdout и callee.stderr как к обычным файлам, что позволяет вышеописанному "решению" работать. Если вы хотите получить callee.returncode, вам придется сделать дополнительный вызов callee.poll().

Будьте осторожны с записью на callee.stdin: если процесс завершился, когда вы это делаете, может возникнуть ошибка (в Linux я получаю IOError: [Errno 32] Broken pipe).

7
ответ дан 24 November 2019 в 16:29
поделиться

Если вы не хотите взаимодействовать с процессом, вы можете использовать модуль подпроцесса.

Пример:

tester.py

import os
import sys

for file in os.listdir('.'):
    print file

sys.stderr.write("Oh noes, a shrubbery!")
sys.stderr.flush()
sys.stderr.close()

testing.py

import subprocess

p = subprocess.Popen(['python', 'tester.py'], stdout=subprocess.PIPE,
                     stdin=subprocess.PIPE, stderr=subprocess.PIPE)

stdout, stderr = p.communicate()
print stdout, stderr

В вашей ситуации вы можете просто сначала записать stdout / stderr в файл. Вы также можете отправлять аргументы своему процессу с помощью связи, хотя я не мог понять, как постоянно взаимодействовать с подпроцессом.

2
ответ дан 24 November 2019 в 16:29
поделиться

Попробуйте следующее:

import sys

class tee-function :

    def __init__(self, _var1, _var2) :

        self.var1 = _var1
        self.var2 = _var2

    def __del__(self) :

        if self.var1 != sys.stdout and self.var1 != sys.stderr :
            self.var1.close()
        if self.var2 != sys.stdout and self.var2 != sys.stderr :
            self.var2.close()

    def write(self, text) :

        self.var1.write(text)
        self.var2.write(text)

    def flush(self) :

        self.var1.flush()
        self.var2.flush()

stderrsav = sys.stderr

out = open(log, "w")

sys.stderr = tee-function(stderrsav, out)
-1
ответ дан 24 November 2019 в 16:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: