我有一些Python代码执行外部应用程序,当应用程序有少量输出时工作正常,但有很多时挂起.我的代码看起来像:
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
errcode = p.wait()
retval = p.stdout.read()
errmess = p.stderr.read()
if errcode:
log.error('cmd failed <%s>: %s' % (errcode,errmess))
Run Code Online (Sandbox Code Playgroud)
文档中的评论似乎表明了潜在的问题.等待,有:
警告:如果子进程生成足够的输出
stdout或stderr管道,以阻止等待OS管道缓冲区接受更多数据,这将导致死锁.使用communicate()以避免这种情况.
虽然在沟通中,我看到:
注意读取的数据缓冲在内存中,因此如果数据大小很大或不受限制,请不要使用此方法.
因此我不清楚如果我有大量数据,我应该使用其中任何一种.它们没有说明在这种情况下我应该使用什么方法.
我确实需要来自exec的返回值并进行解析并使用stdout和stderr.
那么Python中用于执行具有大输出的外部应用程序的等效方法是什么?
我想读一个子进程'stdout的第一个字节,知道它已经开始运行了.之后,我想丢弃所有进一步的输出,这样我就不用担心缓冲区了.
做这个的最好方式是什么?
澄清:我希望子进程继续与我的程序一起运行,我不想等待它终止或类似的东西.理想情况下,有一些简单的方法可以做到这一点,而不是诉诸threading,fork或multiprocessing.
如果我忽略输出流,或者.close()它,如果发送的数据多于它可以容纳在其缓冲区中的数据,则会导致错误.
可能重复:
包装子进程'stdout/stderr
在这个问题中,hanan-n询问是否可以将python子进程输出到stdout,同时还将输出保存在字符串中以便以后处理.在这种情况下,解决方案是遍历每个输出行并手动打印它们:
output = []
p = subprocess.Popen(["the", "command"], stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''):
print(line)
output.append(line)
Run Code Online (Sandbox Code Playgroud)
但是,此解决方案并未概括为您要为stdout和stderr执行此操作的情况,同时满足以下条件:
我查看了子进程文档,但找不到任何可以实现此目的的东西.我能找到的最接近的是添加stderr=subprocess.stdout和使用与上面相同的解决方案,但是我们失去了常规输出和错误之间的区别.有任何想法吗?我猜测解决方案 - 如果有的话 - 将涉及异步读取p.stdout和p.stderr.
这是我想做的一个例子:
p = subprocess.Popen(["the", "command"])
p.wait() # while p runs, the command's stdout and stderr should behave as usual
p_stdout = p.stdout.read() # unfortunately, this will return '' unless you use subprocess.PIPE
p_stderr = p.stderr.read() # ditto
[do something …Run Code Online (Sandbox Code Playgroud) 我正在寻找从python调用shell脚本的方法,并使用日志记录将他们的stdout和stderr写入文件.这是我的代码:
import logging
import tempfile
import shlex
import os
def run_shell_command(command_line):
command_line_args = shlex.split(command_line)
logging.info('Subprocess: \"' + command_line + '\"')
process_succeeded = True
try:
process_output_filename = tempfile.mktemp(suffix = 'subprocess_tmp_file_')
process_output = open(process_output_filename, 'w')
command_line_process = subprocess.Popen(command_line_args,\
stdout = process_output,\
stderr = process_output)
command_line_process.wait()
process_output.close()
process_output = open(process_output_filename, 'r')
log_subprocess_output(process_output)
process_output.close()
os.remove(process_output_filename)
except:
exception = sys.exc_info()[1]
logging.info('Exception occured: ' + str(exception))
process_succeeded = False
if process_succeeded:
logging.info('Subprocess finished')
else:
logging.info('Subprocess failed')
return process_succeeded
Run Code Online (Sandbox Code Playgroud)
我确信无需创建临时文件来存储流程输出就可以实现.有任何想法吗?
我正在研究一个漂亮的小功能:
def startProcess(name, path):
"""
Starts a process in the background and writes a PID file
returns integer: pid
"""
# Check if the process is already running
status, pid = processStatus(name)
if status == RUNNING:
raise AlreadyStartedError(pid)
# Start process
process = subprocess.Popen(path + ' > /dev/null 2> /dev/null &', shell=True)
# Write PID file
pidfilename = os.path.join(PIDPATH, name + '.pid')
pidfile = open(pidfilename, 'w')
pidfile.write(str(process.pid))
pidfile.close()
return process.pid
Run Code Online (Sandbox Code Playgroud)
问题是这process.pid不是正确的PID.它似乎总是比正确的PID低1.例如,它表示该过程始于31729,但ps表示它正在31730运行.每次我尝试将其关闭1.我猜它返回的PID是当前进程的PID ,而不是已启动的PID ,并且新进程获得的"下一个"pid高出1.如果是这种情况,我不能仅仅依靠返回,process.pid …
非常具体的问题(我希望):以下三个代码之间有什么区别?
(我希望它只是第一个不等待子进程完成,而第二个和第三个进行.但我需要确定这是唯一的区别......)
我也欢迎其他评论/建议(虽然我已经很清楚shell=True危险和跨平台限制)
请注意,我已经阅读过Python子进程交互,为什么我的进程可以使用Popen.communicate,但不能使用Popen.stdout.read()?并且我不希望/之后需要与程序交互.
另请注意,我已经阅读了Python Popen.communicate()内存限制的替代品?但是我没有真正得到它......
最后,请注意我知道当一个缓冲区使用一种方法填充一个输出时存在死锁的风险,但我在互联网上寻找清晰的解释时迷路了......
第一个代码:
from subprocess import Popen, PIPE
def exe_f(command='ls -l', shell=True):
"""Function to execute a command and return stuff"""
process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)
stdout = process.stdout.read()
stderr = process.stderr.read()
return process, stderr, stdout
Run Code Online (Sandbox Code Playgroud)
第二个代码:
from subprocess import Popen, PIPE
from subprocess import communicate
def exe_f(command='ls -l', shell=True):
"""Function to execute a command and return stuff"""
process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)
(stdout, stderr) …Run Code Online (Sandbox Code Playgroud) 我有一个与用户交互的程序(就像一个shell),我想以交互方式使用python子进程模块运行它.这意味着,我希望有可能写入stdin并立即从stdout获取输出.我在这里尝试了许多解决方案,但它们似乎都不能满足我的需求.
我编写的代码基于在python中运行交互式命令
import Queue
import threading
import subprocess
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def getOutput(outQueue):
outStr = ''
try:
while True: #Adds output from the Queue until it is empty
outStr+=outQueue.get_nowait()
except Queue.Empty:
return outStr
p = subprocess.Popen("./a.out", stdin=subprocess.PIPE, stout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize = 1)
#p = subprocess.Popen("./a.out", stdin=subprocess.PIPE, stout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True)
outQueue = Queue()
errQueue = Queue()
outThread = Thread(target=enqueue_output, args=(p.stdout, outQueue))
errThread = Thread(target=enqueue_output, args=(p.stderr, errQueue))
outThread.daemon = True
errThread.daemon = True …Run Code Online (Sandbox Code Playgroud) 我有一个python子进程,我正在尝试从中读取输出和错误流.目前我有它的工作,但我只能在读完stderr之后阅读stdout.这是它的样子:
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_iterator = iter(process.stdout.readline, b"")
stderr_iterator = iter(process.stderr.readline, b"")
for line in stdout_iterator:
# Do stuff with line
print line
for line in stderr_iterator:
# Do stuff with line
print line
Run Code Online (Sandbox Code Playgroud)
如您所见,stderrfor循环在stdout循环完成之前无法启动.如何修改它以便能够以正确的顺序读取这两行?
澄清:我仍然需要能够判断一条线是否来自stdout或者stderr因为我的代码中它们的处理方式不同.
我在Python中使用子进程包来运行子进程,我后来需要杀死它.但是,子进程包的文档声明terminate()函数仅在2.6中可用
我们使用2.5运行Linux,出于向后兼容的原因,我无法升级到2.6,有什么替代方案?我猜这些函数是方便的东西.
我在linux机器上运行一个python脚本,它使用subprocess.check_output()创建一个子进程,如下所示:
subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT)
Run Code Online (Sandbox Code Playgroud)
问题是,即使父进程死亡,子进程仍在运行.当父母去世时,我有什么办法可以杀死孩子的过程吗?
python ×10
subprocess ×10
popen ×2
stdout ×2
communicate ×1
interactive ×1
linux ×1
logging ×1
stderr ×1
stdin ×1
stream ×1
wait ×1