Um die bash process substitution zu emulieren:
#!/usr/bin/env python
from subprocess import check_call
check_call('someprogram <(someprocess) <(anotherprocess)',
shell=True, executable='/bin/bash')
In Python, Sie Named Pipes verwenden:
#!/usr/bin/env python
from subprocess import Popen
with named_pipes(n=2) as paths:
someprogram = Popen(['someprogram'] + paths)
processes = []
for path, command in zip(paths, ['someprocess', 'anotherprocess']):
with open(path, 'wb', 0) as pipe:
processes.append(Popen(command, stdout=pipe, close_fds=True))
for p in [someprogram] + processes:
p.wait()
wo named_pipes(n)
ist:
import os
import shutil
import tempfile
from contextlib import contextmanager
@contextmanager
def named_pipes(n=1):
dirname = tempfile.mkdtemp()
try:
paths = [os.path.join(dirname, 'named_pipe' + str(i)) for i in range(n)]
for path in paths:
os.mkfifo(path)
yield paths
finally:
shutil.rmtree(dirname)
Ein anderes und vor Abnutzbare Möglichkeit (keine Notwendigkeit, einen benannten Eintrag auf der Festplatte zu erstellen), um die bash-Prozesssubstitution zu implementieren, ist die Verwendung von /dev/fd/N
Dateinamen (falls verfügbar) als suggested by @Dunes. Auf FreeBSD, fdescfs(5)
(/dev/fd/#
) creates entries for all file descriptors opened by the process. Um die Verfügbarkeit zu testen, führen Sie Folgendes aus:
$ test -r /dev/fd/3 3</dev/null && echo /dev/fd is available
Wenn es fehlschlägt; versuchen /dev/fd
zu proc(5)
Symlink wie es auf einigen Linux-Versionen getan wird:
$ ln -s /proc/self/fd /dev/fd
Hier /dev/fd
basierte Implementierung von someprogram <(someprocess) <(anotherprocess)
bash Befehl:
#!/usr/bin/env python3
from contextlib import ExitStack
from subprocess import CalledProcessError, Popen, PIPE
def kill(process):
if process.poll() is None: # still running
process.kill()
with ExitStack() as stack: # for proper cleanup
processes = []
for command in [['someprocess'], ['anotherprocess']]: # start child processes
processes.append(stack.enter_context(Popen(command, stdout=PIPE)))
stack.callback(kill, processes[-1]) # kill on someprogram exit
fds = [p.stdout.fileno() for p in processes]
someprogram = stack.enter_context(
Popen(['someprogram'] + ['/dev/fd/%d' % fd for fd in fds], pass_fds=fds))
for p in processes: # close pipes in the parent
p.stdout.close()
# exit stack: wait for processes
if someprogram.returncode != 0: # errors shouldn't go unnoticed
raise CalledProcessError(someprogram.returncode, someprogram.args)
Hinweis: auf meinem Ubuntu-Rechner, der subprocess
Code funktioniert nur in Python 3.4+, obwohl pass_fds
seit Python 3.2 verfügbar ist.
verwandte: [Bash Stil Prozess Substitution mit Python Popen] (http://stackoverflow.com/q/15343447/4279) – jfs
auf den Titel bezogen werden: [Wie kann ich subprocess.Popen verwenden, um mehrere Prozesse zu verbinden durch Rohre?] (http://Stackoverflow.com/q/295459/4279) – jfs