Skip to main content
 首页 » 编程设计

python之存储在某个文件中的交互式 Python 脚本输出

2025年05月04日11lexus

如何记录由 Python 脚本完成的所有事件以及从中调用的所有脚本?

我有几个 Bash 脚本,但现在写了一个调用所有这些 Bash 脚本的 Python 脚本。我希望将这些脚本产生的所有输出存储在某个文件中。

该脚本是交互式 Python 脚本,即包含 raw_input 行,所以我不能像 'python script.py | tee log.txt' 用于整个 Python 脚本,因为由于某些原因问题没有出现在屏幕上。

这是调用 shell 脚本之一的脚本的摘录。

    cmd = "somescript.sh" 
    try: 
    retvalue = subprocess.check_call(cmd, shell=True) 
except subprocess.CalledProcessError: 
    print ("script command has been failed") 
    sys.exit("exit from script") 

您认为这里可以做什么?

编辑

基于 Alex 回答的两个子问题:

  1. 如何将问题的答案也存储在输出文件中?例如,在 ok = raw_input(prompt) 行,系统会询问用户问题,我也想记录答案。

  2. 我阅读了有关 Popen 和通信的信息,但没有使用,因为它会将数据缓冲在内存中。这里的输出量很大,我也需要关心标准输出的标准错误。你知道这是否可以用 Popen 和通信方法来处理吗?

请您参考如下方法:

让 Python 自己的 print 同时到达终端和文件并不难:

>>> import sys 
>>> class tee(object): 
...   def __init__(self, fn='/tmp/foo.txt'): 
...     self.o = sys.stdout 
...     self.f = open(fn, 'w') 
...   def write(self, s): 
...     self.o.write(s) 
...     self.f.write(s) 
...  
>>> sys.stdout = tee() 
>>> print('hello world!') 
hello world! 
>>>  
$ cat /tmp/foo.txt 
hello world! 

这应该适用于 Python 2 和 Python 3。

要类似地引导子命令的输出,请不要使用

retvalue = subprocess.check_call(cmd, shell=True) 

它让 cmd 的输出转到它的常规“标准输出”,而是自己抓取并重新发出它,如下所示:

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 
so, se = p.communicate() 
print(so) 
retvalue = p.returncode 

假设您不关心标准错误(仅标准输出)并且 cmd 的输出量相当小(因为 .communicate 缓冲数据在内存中)——如果任一假设都不符合您的确切需求,则很容易进行调整。

编辑:OP 现在已经在对此答案的长评论中阐明了规范:

  • 如何在 存储在输出文件中的问题 还有吗?例如在线 ok = raw_input(prompt) 用户将 问了这个问题,我会 也喜欢记录的答案。

使用如下函数:

def echoed_input(prompt): 
    response = raw_input(prompt) 
    sys.stdout.f.write(response) 
    return response 

而不仅仅是在您的应用程序代码中使用 raw_input(当然,这是专门为配合我上面显示的 tee 类而编写的)。

  • 我阅读了有关 Popen 的信息并进行了交流 并没有使用,因为它缓冲了 内存中的数据。这里的输出量 很大,我需要关心 带标准输出的标准错误 以及。你知道这是不是 可以处理 Popen 和 还有沟通方式?

communicate 没问题,只要您不得到的输出(和标准错误)多于适合内存的大小,例如最多几千兆字节,具体取决于您使用的机器类型。

如果满足这个假设,只需将上面的代码重新编码为:

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,  
                     stderr=subprocess.STDOUT) 
so, se = p.communicate() 
print(so) 
retvalue = p.returncode 

即,只需重定向子命令的标准错误以混合到其标准输出中。

如果您确实需要担心千兆字节(或其他)向您袭来,那么

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,  
                     stderr=subprocess.STDOUT) 
for line in p.stdout: 
  sys.stdout.write(p) 
p.wait() 
retvalue = p.returncode 

(一次获取和发出一行)可能更可取(这取决于 cmd 不期望从其标准 input 得到任何东西,当然...因为,如果它正在期待任何东西,它不会得到它,问题开始变得具有挑战性;-)。