簡體   English   中英

用Python的Popen替換Bash風格的流程

[英]Bash style process substitution with Python's Popen

在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如何自動創建文件描述符,並允許您將程序的輸出傳遞給另一個程序。

現在,我的問題是:如何在子流程模塊中使用Popen使用Python做同樣的事情?

我一直在使用kmers的普通文件並只是讀入其中,但是我的程序現在會在運行時根據用戶參數生成kmers的特定列表。 我想避免手動寫入臨時文件,因為處理文件權限可能會對原始用戶造成問題。

這是我的代碼,用於運行程序並使用實際文件“ kmer_file”捕獲標准輸出

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

為了避免等待所有kmers生成,即同時寫入/讀取kmers,可以在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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM