在BASH中,您可以很容易地将进程的输出重定向到临时文件描述符,并且所有这些都是由BASH自动处理的:
$ mydaemon --config-file <(echo "autostart: True \n daemonize: True")
或者像这样:
$ wc -l <(ls)
15 /dev/fd/63
查看它如何不是stdin重定向:
$ vim <(echo "Hello World")
vim opens a text file containing "Hello world"
$ echo "Hello World" | vim
Vim: Warning: Input is not from a terminal
您可以在第二个示例中看到bash如何自动创建一个文件描述符,并允许您将一个程序的输出传递给另一个程序。
现在我的问题是:如何在Python中使用Popen在子进程模块中做同样的事情?
我一直在使用一个正常的KMES文件,只是读取它,但是我的程序现在在运行时根据用户参数生成一个特定的KMER列表。我想避免手动写入临时文件,因为处理文件权限可能会给原始用户带来问题。
这是我运行程序并用实际文件“kmer_file”捕获stdout的代码
input_file = Popen(["pram_axdnull", str(kmer), input_file, kmer_file], stdout=PIPE)
我创建了一个名为generate_kmers的函数,它返回一个字符串,该字符串可以很容易地写入文件(包括换行符)或stringio。我也有一个独立的Python脚本来做同样的事情。
所以现在我想把它作为我的第三个参数来传递:
这不起作用:
kmer_file = stringIO(generate_kmers(3))
input_file = Popen(["pram_axdnull", str(kmer), input_file, kmer_file], stdout=PIPE)
这也不是:
kmer_file = Popen(["generate_kmers", str(kmer)], stdout=PIPE)
input_file = Popen(["pram_axdnull", str(kmer), input_file, kmer_file.stdout], stdout=PIPE)
所以我没主意了。
有人知道解决这个问题的好方法吗?我想使用shell=true选项并使用实际的bashism谢谢您!
最佳答案
如果pram_axdnull
理解"-"
约定的意思是:“从stdin读取”,那么您可以:
p = Popen(["pram_axdnull", str(kmer), input_filename, "-"],
stdin=PIPE, stdout=PIPE)
output = p.communicate(generate_kmers(3))[0]
如果输入是由外部过程生成的:
kmer_proc = Popen(["generate_kmers", str(kmer)], stdout=PIPE)
p = Popen(["pram_axdnull", str(kmer), input_filename, "-"],
stdin=kmer_proc.stdout, stdout=PIPE)
kmer_proc.stdout.close()
output = p.communicate()[0]
如果
pram_axdnull
不理解"-"
惯例:import os
import tempfile
from subprocess import check_output
with tempfile.NamedTemporaryFile() as file:
file.write(generate_kmers(3))
file.delete = False
try:
p = Popen(["pram_axdnull", str(kmer), input_filename, file.name],
stdout=PIPE)
output = p.communicate()[0]
# or
# output = check_output(["pram_axdnull", str(kmer), input_filename,
file.name])
finally:
os.remove(file.name)
使用外部进程生成临时文件:
from subprocess import check_call
with tempfile.NamedTemporaryFile() as file:
check_call(["generate_kmers", str(kmer)], stdout=file)
file.delete = False
为了避免等待生成所有KMER,即同时写入/读取KMER,可以在UNIX上使用
os.mkfifo()
(由@ cDARKE建议):import os
import shutil
import tempfile
from contextlib import contextmanager
from subprocess import Popen, PIPE
@contextmanager
def named_pipe():
dirname = tempfile.mkdtemp()
try:
path = os.path.join(dirname, 'named_pipe')
os.mkfifo(path)
yield path
finally:
shutil.rmtree(dirname)
with named_pipe() as path:
p = Popen(["pram_axdnull", str(kmer), input_filename, path],
stdout=PIPE) # read from path
with open(path, 'wb') as wpipe:
kmer_proc = Popen(["generate_kmers", str(kmer)],
stdout=wpipe) # write to path
output = p.communicate()[0]
kmer_proc.wait()