需要使用subprocess模块对两个NamedTemporaryFiles运行diff命令

1 投票
3 回答
5050 浏览
提问于 2025-04-18 03:46

我正在尝试对两个命名的临时文件进行比较,我没有使用difflib,因为它的输出和Linux的diff不一样。
当我运行这段代码时,它没有输出任何内容。我尝试对普通文件进行比较,这样是可以正常工作的。

#using python 2.6
temp_stage = tempfile.NamedTemporaryFile(delete = False)
temp_prod = tempfile.NamedTemporaryFile(delete = False)
temp_stage.write(stage_notes)
temp_prod.write(prod_notes)

#this does not work, shows no output, tried both call and popen
subprocess.Popen(["diff", temp_stage.name, temp_prod.name])

#subprocess.call(["diff", temp_stage.name, temp_prod.name])

3 个回答

2

我建议你跳过临时文件的处理,因为使用NTF(非临时文件)时,你还是得处理清理工作。你可以新建一个文件,把你的数据写进去,然后关闭这个文件。接着,刷新一下缓存,然后再调用子进程的命令。看看这样能不能让它运行。

f=open('file1.blah','w')
f2=open('file2.blah','w')
f.write(stage_notes)
f.flush()
f.close()
f2.write(prod_notes)
f2.flush()
f2.close()

然后运行你的子进程调用

3

跟你提到的.flush()问题没关系,你可以通过标准输入(stdin)传递一个文件,而不是把数据写到硬盘上:

from tempfile import NamedTemporaryFile
from subprocess import Popen, PIPE

with NamedTemporaryFile() as file:
    file.write(prod_notes)
    file.flush()
    p = Popen(['diff', '-', file.name], stdin=PIPE)
    p.communicate(stage_notes) # diff reads the first file from stdin

if p.returncode == 0:
    print('the same')
elif p.returncode == 1:
    print('different')
else:
    print('error %s' % p.returncode)

diff命令在输入文件名是-时,会从标准输入读取数据。

如果你使用命名管道,那就完全不需要把数据写到硬盘上了:

from subprocess import Popen, PIPE
from threading import Thread

with named_pipe() as path:
    p = Popen(['diff', '-', path], stdin=PIPE)
    # use thread, to support content larger than the pipe buffer
    Thread(target=p.communicate, args=[stage_notes]).start()
    with open(path, 'wb') as pipe:
        pipe.write(prod_notes)

if p.wait() == 0:
    print('the same')
elif p.returncode == 1:
    print('different')
else:
    print('error %s' % p.returncode)

这里named_pipe()的上下文管理器是这样定义的:

import os
import tempfile
from contextlib import contextmanager
from shutil import rmtree

@contextmanager
def named_pipe(name='named_pipe'):
    dirname = tempfile.mkdtemp()
    try:
        path = os.path.join(dirname, name)
        os.mkfifo(path)
        yield path
    finally:
        rmtree(dirname)

命名管道的内容不会接触到硬盘。

4

你需要通过调用 flush() 来强制将文件写入磁盘;否则,你写入文件的数据可能只存在于一个临时的存储区中。

实际上,如果你这样做了,甚至可以使用 delete = True,前提是没有其他理由需要保留这些文件。这样可以继续享受使用临时文件的好处。

#!/usr/bin/python2
temp_stage = tempfile.NamedTemporaryFile(delete = True)
temp_prod = tempfile.NamedTemporaryFile(delete = True)
temp_stage.write(stage_notes)
temp_prod.write(prod_notes)

temp_stage.flush()
temp_prod.flush()

subprocess.Popen(["diff", temp_stage.name, temp_prod.name])

撰写回答