I'd like to execute this series of commands from within a python program.

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

I've been successful with the following:

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

What I haven't been able to figure out his how to redirect multiple stdouts to the stdin of comm -12.

I thought perhaps:

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

Thoughts?

share|improve this question
feedback

1 Answer

First, let’s look at how the shell’s <(command) command substitution works. The command is started with the output pointing to a newly created pipe. Then the pipe is passed on the command line as a filename to the outer command.

For example:

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

Shows that the shell starts date with output to a pipe, and then passes the pseudofile /dev/fd/63 referring to the new pipe at file descriptor 63 as the actual command line argument.


To get the same behaviour in Python, we can implement the same thing:

from subprocess import *

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

print

6 /dev/fd/3

You could write a class to make it easier to do. This uses a with statement and temporarily keeps references to each spawned process, because otherwise the pipes would get closed when the process objects got garbage-collected.

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'])])])
share|improve this answer
feedback

Your Answer

 
or
required, but never shown
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.