하위 프로세스를 사용할 때 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://devlishgenius.blogspot.com/2008/10/logging-in-real-time-in-python.html(mkfifo 는 Unix에서만 작동 함)
- http://blog.kagesenshi.org/2008/02/teeing-python-subprocesspopen-output.html (전혀 작동하지 않음)
다이어그램 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)
이것은 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
).
프로세스와 상호 작용하지 않으려면 하위 프로세스 모듈을 잘 사용할 수 있습니다.
예:
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:
- This util captures stdout/stderr always
- This util provides an option to echo stdout/stderr to stdout/stderr for the process
- 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()
'code' 카테고리의 다른 글
함수 내에서 클래스를 만들고 포함하는 함수의 범위에 정의 된 함수에 액세스 (0) | 2020.12.02 |
---|---|
파이썬에서 희소 3D 행렬 / 배열? (0) | 2020.12.02 |
range (len (a))가 필요합니까? (0) | 2020.12.02 |
Boost를 사용하여 C ++ 14 스타일 자동 반환 유형을 달성하려면 어떻게해야합니까? (0) | 2020.12.02 |
Chrome 프로파일 러의 '최적화되지 않음'경고는 무엇을 의미하나요? (0) | 2020.12.02 |