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'])])])