code

하위 프로세스를 사용할 때 Python에서 티 동작을 복제하는 방법은 무엇입니까?

codestyles 2020. 12. 2. 21:23
반응형

하위 프로세스를 사용할 때 Python에서 티 동작을 복제하는 방법은 무엇입니까?


콘솔에서 명령을 숨기지 않고 파일에 명령 출력을 저장할 수있는 Python 솔루션을 찾고 있습니다.

참고 : Python intertools 모듈에서 이름이 같은 함수가 아니라 tee (Unix 명령 줄 유틸리티) 에 대해 묻습니다 .

세부

  • Python 솔루션 (을 호출하지 않음 tee, Windows에서는 사용할 수 없음)
  • 호출 된 프로세스에 대한 stdin에 입력을 제공 할 필요가 없습니다.
  • 호출 된 프로그램을 제어 할 수 없습니다. 내가 아는 것은 stdout 및 stderr에 무언가를 출력하고 종료 코드와 함께 반환한다는 것입니다.
  • 외부 프로그램 (하위 프로세스)을 호출 할 때 작동하려면
  • 모두 작동하도록 stderr하고stdout
  • stdout과 stderr 중 하나만 콘솔에 표시하거나 다른 색상을 사용하여 stderr를 출력하려고 할 수 있기 때문에 stdout과 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--

예상되는 출력은 라인을 정렬하는 것이 었습니다. 비고, 하나의 PIPE 만 사용하도록 Popen을 수정하는 것은 허용되지 않습니다. 실생활에서는 stderr 및 stdout으로 다른 작업을 수행하고 싶기 때문입니다.

또한 두 번째 경우에도 실시간으로 얻을 수 없었고 실제로 모든 결과는 프로세스가 끝났을 때 받았습니다. 기본적으로 Popen은 버퍼를 사용하지 않아야합니다 (bufsize = 0).


나는 이것이 다소 오래된 게시물이라는 것을 알지만 누군가가 여전히 이것을 수행하는 방법을 찾고있는 경우를 대비하여 :

proc = subprocess.Popen(["ping", "localhost"], 
                        stdout=subprocess.PIPE, 
                        stderr=subprocess.PIPE)

with open("logfile.txt", "w") as log_file:
  while proc.poll() is None:
     line = proc.stderr.readline()
     if line:
        print "err: " + line.strip()
        log_file.write(line)
     line = proc.stdout.readline()
     if line:
        print "out: " + line.strip()
        log_file.write(line)

이것은 teePython에 대한 간단한 포팅입니다 .

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.stdoutcallee.stderr일반 파일 작업에 대한 위의 "솔루션"을 가능하게있다. 을 받으려면에 callee.returncode추가로 전화를 걸어야합니다 callee.poll().

쓰기에주의하십시오 callee.stdin: 프로세스가 종료되면 오류가 발생할 수 있습니다 (Linux에서는 IOError: [Errno 32] Broken pipe).


프로세스와 상호 작용하지 않으려면 하위 프로세스 모듈을 잘 사용할 수 있습니다.

예:

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

In your situation you can simply write stdout/stderr to a file first. You can send arguments to your process with communicate as well, though I wasn't able to figure out how to continually interact with the subprocess.


There are subtle problems/bugs in python related to subprocess.PIPE: http://bugs.python.org/issue1652

Apparently this was fixed in python3+, but not in python 2.7 and older. For that you need to use: code.google.com/p/python-subprocess32/


This is how it can be done

import sys
from subprocess import Popen, PIPE

with open('log.log', 'w') as log:
    proc = Popen(["ping", "google.com"], stdout=PIPE, encoding='utf-8')
    while proc.poll() is None:
        text = proc.stdout.readline() 
        log.write(text)
        sys.stdout.write(text)

Try this :

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)

I wrote a thing that wraps shell commands in Python.

Key advantages:

  1. This util captures stdout/stderr always
  2. This util provides an option to echo stdout/stderr to stdout/stderr for the process
  3. When echoing stdout/stderr the out/err there is no delay

Key disadvantage:

  • Only works on bash/unix

source: https://gist.github.com/AndrewHoos/9f03c74988469b517a7a


My solution isn't elegant, but it works.

You can use powershell to gain access to "tee" under WinOS.

import subprocess
import sys

cmd = ['powershell', 'ping', 'google.com', '|', 'tee', '-a', 'log.txt']

if 'darwin' in sys.platform:
    cmd.remove('powershell')

p = subprocess.Popen(cmd)
p.wait()

참고URL : https://stackoverflow.com/questions/2996887/how-to-replicate-tee-behavior-in-python-when-using-subprocess

반응형