Để cạnh tranh với bash process substitution:
#!/usr/bin/env python
from subprocess import check_call
check_call('someprogram <(someprocess) <(anotherprocess)',
shell=True, executable='/bin/bash')
Trong Python, bạn có thể sử dụng tên Ống:
#!/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()
nơi named_pipes(n)
là:
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)
Một và nhiều hơn nữa trước cách có thể lên men (không cần phải tạo một mục có tên trên đĩa) để thực hiện thay thế tiến trình bash là sử dụng tên tệp /dev/fd/N
(nếu chúng có sẵn) là suggested by @Dunes. Trên FreeBSD, fdescfs(5)
(/dev/fd/#
) creates entries for all file descriptors opened by the process. Để kiểm tra tính khả dụng, hãy chạy:
$ test -r /dev/fd/3 3</dev/null && echo /dev/fd is available
Nếu không thành công; cố gắng liên kết mềm /dev/fd
để proc(5)
vì nó được thực hiện trên một số Linuxes:
$ ln -s /proc/self/fd /dev/fd
Dưới đây là /dev/fd
thực hiện dựa trên các lệnh someprogram <(someprocess) <(anotherprocess)
bash:
#!/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)
Lưu ý: trên máy tính Ubuntu của tôi, mã subprocess
chỉ hoạt động trong Python 3.4+, mặc dù pass_fds
khả dụng kể từ Python 3.2.
liên quan: [Bash quá trình phong cách thay thế với Popen Python] (http://stackoverflow.com/q/15343447/4279) – jfs
liên quan đến tiêu đề: [Làm thế nào để sử dụng subprocess.Popen để kết nối nhiều quy trình bằng đường ống?] (http://stackoverflow.com/q/295459/4279) – jfs