gpt4 book ai didi

python - 子进程中的多个管道

转载 作者:太空狗 更新时间:2023-10-29 22:13:08 25 4
gpt4 key购买 nike

我正在尝试在 ruffus 管道中使用 Sailfish,它将多个 fastq 文件作为参数。我在 python 中使用子进程模块执行 Sailfish,但是 <()即使我设置了 shell=True,子进程调用也不起作用.

这是我想使用 python 执行的命令:

sailfish quant [options] -1 <(cat sample1a.fastq sample1b.fastq) -2 <(cat sample2a.fastq sample2b.fastq) -o [output_file]

或(最好):

sailfish quant [options] -1 <(gunzip sample1a.fastq.gz sample1b.fastq.gz) -2 <(gunzip sample2a.fastq.gz sample2b.fastq.gz) -o [output_file]

概括:

someprogram <(someprocess) <(someprocess)

我将如何在 python 中执行此操作?子流程是正确的方法吗?

最佳答案

模拟bash process substitution :

#!/usr/bin/env python
from subprocess import check_call

check_call('someprogram <(someprocess) <(anotherprocess)',
shell=True, executable='/bin/bash')

在 Python 中,您可以使用命名管道:

#!/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()

哪里named_pipes(n)是:

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)

实现 bash 进程替换的另一种更可取的方法(无需在磁盘上创建命名条目)是使用 /dev/fd/N文件名(如果可用)为 suggested by @Dunes .在 FreeBSD 上, fdescfs(5) ( /dev/fd/# ) creates entries for all file descriptors opened by the process .要测试可用性,请运行:

$ test -r /dev/fd/3 3</dev/null && echo /dev/fd is available

如果失败;尝试符号链接(symbolic link) /dev/fd proc(5) 正如在某些 Linux 上所做的那样:

$ ln -s /proc/self/fd /dev/fd

这是 /dev/fd基于 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)

注意:在我的 Ubuntu 机器上,subprocess代码仅适用于 Python 3.4+,尽管 pass_fds从 Python 3.2 开始可用。

关于python - 子进程中的多个管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28840575/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com