python Subprocess的使用

1、subprocess以及經常使用的封裝函數, 鏈接文檔,Popen不用wait用communicate
運行python的時候,咱們都是在建立並運行一個進程。像Linux進程那樣,一個進程能夠fork一個子進程,並讓這個子進程exec另一個程序。在Python中,咱們經過標準庫中的subprocess包來fork一個子進程,並運行一個外部的程序。
subprocess包中定義有數個建立子進程的函數,這些函數分別以不一樣的方式建立子進程,因此咱們能夠根據須要來從中選取一個使用。另外subprocess還提供了一些管理標準流(standard stream)和管道(pipe)的工具,從而在進程間使用文本通訊html

subprocess模塊是python從2.4版本開始引入的模塊。主要用來取代一些舊的模塊方法,如os.system、os.spawn*、os.popen*、commands.*等。subprocess經過子進程來執行外部指令,並經過input/output/error管道,獲取子進程的執行的返回信息python

調用subprocess的推薦方法是對於它能夠處理的全部使用場景都使用run()函數。run()函數是在Python 3.5中添加的,若是在老版本中使用,須要下載並擴展。shell

pip install subprocess.run

使用方法app

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False,env=None)

運行args描述的命令。等待命令完成,而後返回一個CompletedProcess實例。class subprocess.CompletedProcess表示從run()返回的值,表示已完成的進程。ide

完整的函數形式很大程度上與Popen構造函數相同 —— 除timeout、input和check以外,該函數的全部參數都傳遞給Popen接口。函數

參數

args

args是全部調用所必需的,應該爲一個字符串或一個程序參數序列list。一般傾向提供參數序列,由於它容許這個模塊來處理任何所需的轉義和引用參數(例如,容許文件名中的空格)。若是傳遞單個字符串,shell必須爲True(見下文),不然字符串必須簡單地命名要執行的程序而不指定任何參數。工具

stdin、stdout和stderr

stdin、stdout和stderr分別指定執行程序的標準輸入標準輸出標準錯誤文件句柄。有效值有PIPEDEVNULL,一個存在的文件描述器(正整數),一個存在的文件對象和None。PIPE表示應該爲子進程建立新的管道。DEVNULL表示將使用特殊文件os.devnull。使用默認設置None,則不會發生重定向;子進程的文件句柄將從父進程繼承。此外,stderr能夠是STDOUT,表示來自子進程的標準錯誤數據應該捕獲到與stdout相同的文件句柄中。spa

shell

若是shell是True,則將經過shell執行指定的命令。若是你使用Python主要是因爲它能提供大多數系統shell不能提供的加強的控制流,而且仍然但願方便地訪問其餘shell功能,如shell管道、文件名通配符、環境變量擴展和擴展〜到用戶的主目錄,這會頗有用。code

>>> from subprocess import run

>>> print run('uname -r')
3.7.0-7-generic

>>> print run('uname -r').stdout
3.7.0-7-generic

>>> run('uname -a').status
0

>>> print run('rm not_existing_directory').stderr
rm: cannot remove `not_existing_directory': No such file or directory

>>> print run('ls -la', 'wc -l')
14

>>> print run('ls -la', 'wc -l', 'wc -c')
3

>>> run('ls -la', 'wc -l', 'wc -c')
ls -la | wc -l | wc -c

>>> print run('ls -la').stdout.lines
['total 20',
'drwxrwxr-x 3 user user 4096 Dec 20 22:55 .',
'drwxrwxr-x 5 user user 4096 Dec 20 22:57 ..',
'drwxrwxr-x 2 user user 4096 Dec 20 22:37 dir',
'-rw-rw-r-- 1 user user    0 Dec 20 22:52 file']

只是執行一些指令的時候經過subprocess.run 便可。能夠指定stdout,stderr,cwd(代碼工做路徑),env(環境變量)orm

def get_path_env(kaldi=DIR.KALDI): #  在kaldi內部 注意添加環境變量
    old_path = os.environ['PATH']
    ivectorbin_dir = os.path.join(kaldi, 'src', 'ivectorbin')
    bin_dir = os.path.join(kaldi, 'src', 'bin')
    new_path = "{}:{}:{}".format(ivectorbin_dir, bin_dir, old_path)
    return {"PATH": new_path}

env = get_path_env() ,env = {'PATH':$PATH} 這種形式。

 

有時候須要將一個進程的輸入當作另一個進程的輸出,用到subprocess.Popen

import subprocess
child1 = subprocess.Popen(["cat","/etc/passwd"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["grep","0:0"],stdin=child1.stdout, stdout=subprocess.PIPE)
out = child2.communicate()
def transform(xvector_scp_fp, test_scp_fp, test_ark_fp, sre16_major_dir=None, sre_combined_dir=None):
    """
    Transform xvector from dimension of 600 to vecotr of dimension 150. 
    The actual dimensions are decided by `transform.mat`.
    
    Params:
        `sre16_major_dir`: The official `xvectors_sre16_major` directory, which contains `mean.vec`;
        `sre_combined_dir`: The official `xvectors_sre_combined` directory, which contains `transform.mat`;
        `xvector_scp_fp`: scp file path for xvectors to be transformed;
        `test_scp_fp`: location of the destination file path

    NOTE: Here we generate scp file and ark file, instead of only ark file. The reason is to accommandate
    the case where a lot of xvectors are invloved. Since xvector scp file is 
    created by default, we don't have to consider when there is not xvector scp file.
    """
    sre16_major_dir = sre16_major_dir or path.join(DIR.CONSTDIR, 'xvectors_sre16_major')
    sre_combined_dir = sre_combined_dir or path.join(DIR.CONSTDIR, 'xvectors_sre_combined')

    env = get_path_env() # 執行路徑對應第69行,run_faiss.sh
    subtract_cmd = ['ivector-subtract-global-mean']
    mean_vec_dir = path.join(sre16_major_dir, 'mean.vec')
    subtract_cmd.append(mean_vec_dir)
    subtract_cmd.append("scp:{}".format(xvector_scp_fp))
    subtract_cmd.append("ark:-")

    p1 = subprocess.Popen(subtract_cmd, stdout=subprocess.PIPE, env=env, stderr=subprocess.DEVNULL) # p1.stdout

    trans_cmd = ['transform-vec']
    trans_mat_fp = path.join(sre_combined_dir, 'transform.mat')
    trans_cmd.append(trans_mat_fp)
    trans_cmd.append("ark:-")
    trans_cmd.append("ark:-")
    
    p2 = subprocess.Popen(trans_cmd, stdin=p1.stdout, stdout=subprocess.PIPE, env=env, stderr=subprocess.DEVNULL)

    norm_cmd = ['ivector-normalize-length']
    norm_cmd.append('ark:-')
    dest = "ark,scp:{},{}".format(test_ark_fp, test_scp_fp)
    norm_cmd.append(dest)

    p3 = subprocess.Popen(norm_cmd, stdin=p2.stdout, stdout=subprocess.PIPE, env=env,stderr=subprocess.PIPE)
    
    # wait for p3 to execute
    rv = p3.communicate()[0]
    if p3.returncode != 0:
        raise XvectorTransformationError(p3.stdout, p3.stderr)

p3.communicate()

p3.returncode != 0

rv.returncode != 0

class PldaScoreError(Exception):
    """plda score error"""


def cmd_err(err_cls): #  添加報警錯誤,plda_scores_error
    def outer(fn):
        def inner(*args, **kwargs):
            rv = fn(*args, **kwargs)
            if rv.returncode != 0:
                err_msg = rv.stdout + rv.stderr # 報警錯誤信息顯示,
                if type(err_msg) is bytes:
                    err_msg = err_msg.decode() 
                print(err_msg)
                raise err_cls
            else:
                return rv
        return inner
    return outer

@cmd_err(PldaScoreError)
def score(enroll_ark_fp, test_ark_fp, trials_fp, score_fp, log_dir=None, sre16_major_dir=default_sre16, cwd=DIR.KALDIROOT):  # 不須要 num_utts.ark 文件
    """
    Params:
        `sre16_major_dir`: the directory where `plda_adapt` locates
        `enroll_ark_fp`: enroll ark file path
        `test_ark_fp`: test ark file path
        `trials_fp`: trials file path
        `score_fp`: the file path for the generated score file

    """
    
    log_dir = log_dir or (score_fp + ".log")
    cmd = ['utils/run.pl']
    cmd.append(log_dir)
    cmd.append("ivector-plda-scoring")
    cmd.append("--normalize-length=true")
    plda_fp = path.join(sre16_major_dir, 'plda_adapt')
    plda_sub_cmd = "ivector-copy-plda --smoothing=0.0 {} - |".format(plda_fp)
    cmd.append(plda_sub_cmd)
    cmd.append("ark:{}".format(enroll_ark_fp))
    cmd.append("ark:{}".format(test_ark_fp))
    cmd.append(trials_fp)
    cmd.append(score_fp)
    env = get_path_env()
    return subprocess.run(cmd, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)  # cwd  設定子進程當前工做目錄,env  用於指定子進程環境變量,env
相關文章
相關標籤/搜索