将命令重定向到Python中的另一个输入

7 投票
4 回答
5244 浏览
提问于 2025-04-11 09:15

我想在Python中实现这个功能:

gvimdiff <(hg cat file.txt) file.txt

(hg cat file.txt 会输出 file.txt 的最新提交版本)

我知道怎么把文件传给 gvimdiff,但它不接受另一个文件:

$ hg cat file.txt | gvimdiff file.txt -
Too many edit arguments: "-"

接下来是 Python 的部分...

# hgdiff.py
import subprocess
import sys
file = sys.argv[1]
subprocess.call(["gvimdiff", "<(hg cat %s)" % file, file])

当调用 subprocess 时,它只是把 <(hg cat file) 当作文件名传给 gvimdiff

那么,有没有办法像 bash 那样重定向一个命令呢?为了简单起见,只需把一个文件的内容输出并重定向到 diff:

diff <(cat file.txt) file.txt

4 个回答

2

还有一个叫做命令模块的东西:

import commands

status, output = commands.getstatusoutput("gvimdiff <(hg cat file.txt) file.txt")

如果你想在命令运行的时候实时获取数据,还有一组叫做popen的函数可以使用。

2

这实际上是一个在文档中的例子:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

这对你来说意味着:

import subprocess
import sys

file = sys.argv[1]
p1 = Popen(["hg", "cat", file], stdout=PIPE)
p2 = Popen(["gvimdiff", "file.txt"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

这样做就不再依赖于Linux特有的/proc/self/fd这些东西了,这样可能在其他类Unix系统上也能运行,比如Solaris和BSD(包括MacOS),甚至可能在Windows上也能用。

10

这是可以实现的。不过,从Python 2.5开始,这种机制只适用于Linux系统,不能在其他系统上使用:

import subprocess
import sys

file = sys.argv[1]
p1 = subprocess.Popen(['hg', 'cat', file], stdout=subprocess.PIPE)
p2 = subprocess.Popen([
    'gvimdiff',
    '/proc/self/fd/%s' % p1.stdout.fileno(),
    file])
p2.wait()

不过,针对diff这个具体情况,你可以直接从标准输入中获取其中一个文件,这样就不需要使用那种类似bash的功能了:

file = sys.argv[1]
p1 = subprocess.Popen(['hg', 'cat', file], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['diff', '-', file], stdin=p1.stdout)
diff_text = p2.communicate()[0]

撰写回答