使用subprocess.Popen运行需要多个输入重定向的unix工具

时间:2013-01-22 16:57:07

标签: python shell unix

我想在python程序中执行这一系列命令。

wc -l <(comm -12 <(sort file1.txt) <(sort file2.txt))

我已成功完成以下任务:

sort_a = Popen("sort file1.txt", shell=False, stdout=PIPE)
count = Popen(["wc", "-l"], shell=False, stdout=PIPE, stdin=sort_a.stdin)

我无法弄清楚他如何将多个标准重定向到comm -12的标准输入。

我想也许:

compare = Popen(["comm", "-12"], shell=False, stdout=PIPE, stdin=[sort_a.stdin, sort_b.stdin])

思想?

1 个答案:

答案 0 :(得分:1)

首先,让我们看看shell的<(command)命令替换是如何工作的。该 命令以指向新创建的管道的输出开始。那么 pipe在命令行上作为 filename 传递给外部命令。

例如:

$ echo wc -w <(date)
wc -l /dev/fd/63

显示shell启动date并输出到管道,然后传递 伪文件/dev/fd/63将文件描述符63处的新管道称为实际命令行参数。


要在Python中获得相同的行为,我们可以实现相同的功能:

from subprocess import *

date = Popen(['date'], stdout=PIPE)
Popen(["wc", "-w", "/dev/fd/%d" % date.stdout.fileno()])

打印

6 /dev/fd/3

你可以编写一个类来使它更容易。这使用with statement并临时保留对每个衍生进程的引用,因为否则当进程对象被垃圾收集时管道将被关闭。

from subprocess import *

class CommandSubstituter(object):
    def __init__(self):
        self._procs = []

    def __enter__(self):
        return self

    def __exit__(self, *exc_info):
        pass

    def subst(self, *args, **kwargs):
        proc = Popen(*args, stdout=PIPE, **kwargs)
        self._procs.append(proc)
        return "/dev/fd/%d" % proc.stdout.fileno()

with CommandSubstituter() as c:
    Popen(['wc', '-l',
           c.subst(['comm', '-12',
                    c.subst(['sort', 'file1.txt']),
                    c.subst(['sort', 'file2.txt'])])])