如何在没有任何缓冲的情况下将python subprocess命令中的stdout转换为文件?

时间:2014-11-12 21:54:15

标签: python logging subprocess buffer tail

我正在尝试使用subprocess命令将其stdout输出发送到日志文件。 我希望用户能够使用tail -f logfile同时查看日志。

但是,我发现子进程模块在写入文件之前很长时间都在缓冲输出日志。 有没有办法避免这种缓冲行为?

file_stdout=open("/var/log/feeder.log","w")
file_stderr=open("/var/log/feeder.err","w")
proc = subprocess.Popen("python /etc/feeder/feeder.py -i " + input_file + " -o " + output_file + " -r " + str(rate) + " -l " +str(lines), stdout=file_stdout, stderr=file_stderr, shell=True)

当我运行tail -f /var/log/feeder.log时,我希望看到流输出。 有没有办法实现这个目标?

3 个答案:

答案 0 :(得分:2)

  

这里file_stdout是/var/log/feeder.log

不,不是。您不能将字符串作为stdout传递。正如the docs所述。它需要一个文件对象或一个文件描述符(一个数字)。

因此,问题几乎可以肯定是打开文件的方式,而您尚未向我们展示。我猜你是用open函数做的,你把buffering参数作为默认值。正如文档所说:

  

如果未给出 buffering 参数,则默认缓冲策略的工作方式如下:

     
      
  • 二进制文件以固定大小的块缓冲;使用启发式方法选择缓冲区的大小,尝试确定底层设备的“块大小”并回退到io.DEFAULT_BUFFER_SIZE。在许多系统上,缓冲区的长度通常为4096或8192字节。

  •   
  • “交互式”文本文件(isatty()返回True的文件)使用行缓冲。其他文本文件使用上述策略用于二进制文件。

  •   

(这是open的Python 3.x版本; 2.x中的情况有所不同,但基本问题是等效的,解决方案也是如此。)

因此,它将以大块写入,例如8192字节。

如果您想要无缓冲输出,可以使用buffering=0(当然也一定要以二进制模式打开文件)。或者只使用os.open并传递fd,让subprocess创建自己的文件对象。


虽然我们正在使用它,你可能不应该使用shell=True(shell理论上可以引入它自己的缓冲 - 更重要的是,它对你没有任何好处,它会导致所有例如,如果这些字符串中的任何一个字符串中都有空格,则会出现各种问题。此外,您可能希望使用sys.executable代替'python'作为程序名称;这确保了用于运行父脚本的相同版本的Python也被用来运行子脚本,而不是任何版本的Python恰好是PATH

答案 1 :(得分:0)

您使用subprocess.Popen错误。

proc = subprocess.Popen(["python", "/etc/feeder/feeder.py",
    "-i", input_file,
    "-o", output_file,
    "-r", str(rate),
    "-l", str(lines)],
    stdout=file_stdout, stderr=file_stderr)

Subprocess不会缓冲任何东西。被调用的python进程执行缓冲。您必须使用sys.stdout.flush()中的/etc/feeder/feeder.py将数据写入文件。

答案 2 :(得分:0)

这里:你需要给文件描述符而不是文件,文件必须以附加模式打开

file_stdout = open('output_log','a+')
file_stderr = open('error_log','a+')
proc = subprocess.Popen("python /etc/feeder/feeder.py -i " + input_file + " -o " + output_file + " -r " + str(rate) + " -l " +str(lines), stdout=file_stdout, stderr=file_stderr)

这是演示: Here is demo