Python subprocess.check_call - 如何将stdout和stderr同时重定向到屏幕和日志文件?

4
我使用Python 2.7。以下是我目前从Python启动其他程序并将STDOUT和STERR重定向到LOGFILE的方法:
    try:
    # Execute command and print content to LOGFILE
        tempname = os.path.abspath('./text.txt')
        TEMPFILE = open(tempname, 'wb')
        print 'Executing: ', command
        subprocess.check_call(command, shell = True, stdout = TEMPFILE, stderr = TEMPFILE)
        TEMPFILE.close()
        LOGFILE.write(open(tempname, 'rU').read())
        LOGFILE.close()
        os.remove(tempname)
    except Exception as errmsg:
    # If fails then print errors to LOGFILE
        TEMPFILE.close()
        LOGFILE.write(open(tempname, 'rU').read())
        os.remove(tempname)
        print messages.crit_error_bad_command % command, '\n', str(errmsg)
        print >> LOGFILE, messages.crit_error_bad_command % command, '\n', str(errmsg)
        LOGFILE.close() 

首先,我不确定我的上述脚本是否是最佳解决方案。我必须使用临时文件,因为即使subprocess.check_call调用失败,我也想捕获日志。如果您有改进上述脚本的想法,我会很感激。
此外,我想将标准输出和标准错误输出正常显示在屏幕上,并将它们记录到日志文件中。我该怎么做?请注意,如果我不指定标准输出,我会在屏幕上看到像“出现错误,您是否要继续[y/n]?”这样的内容,然后我可以对其进行反应。但现在由于所有内容都被记录到日志中,我无法在屏幕上看到任何内容。回答我的问题应该能够帮助解决这个问题。
谢谢。

使用 logging 模块怎么样? - brandizzi
2
你可以使用 subprocess Popen.communicate(),它会返回 stdout,stderr。这样你就可以对它进行任何想要的操作(记录、打印等)。 - TJD
进一步补充@TJD所说,check_call是一个方便的方法。对于这种情况来说太过有限,因此您应该使用Popen对象。 - jdi
你们能否用代码示例详细说明一下?我对Popen不熟悉。 - cinny
使用Popen,subprocess会等待进程完全完成后才继续执行下一个Python命令吗?如果可能,请提供完整的答案。谢谢。 - cinny
你想实时手动回答子进程的问题,还是提前准备好答案? - jfs
1个回答

1
我会在屏幕上看到类似“出现错误,是否继续 [y/n]?”的信息,然后我可以做出反应。
要重定向子进程的标准输出并手动或使用预定义的答案与进程交互,您可以使用pexpect
from contextlib import closing
import pexpect

with open('text.txt', 'rb') as logfile:
    with closing(pexpect.spawn(command, logfile=logfile)) as child:
        # call here child.expect(), child.sendline(), child.interact(), etc

使用subprocess.Popen实现相同的功能并不容易


实际上,我通常不希望必须进行交互,这也是我最初的方法。但是,有时候情况超出了我的控制,而且如果无法看到问题,程序似乎会挂起,这是不好的。 - cinny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接