zoukankan      html  css  js  c++  java
  • python Subprocess的使用

    一、subprocess以及常用的封装函数, 连接文档,Popen不用wait用communicate
    运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
    subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信

    subprocess模块是python从2.4版本开始引入的模块。主要用来取代一些旧的模块方法,如os.system、os.spawn*、os.popen*、commands.*等。subprocess通过子进程来执行外部指令,并通过input/output/error管道,获取子进程的执行的返回信息

    调用subprocess的推荐方法是对于它可以处理的所有使用场景都使用run()函数。run()函数是在Python 3.5中添加的,如果在老版本中使用,需要下载并扩展。

    pip install subprocess.run

    使用方法

    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()返回的值,表示已完成的进程。

    完整的函数形式很大程度上与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相同的文件句柄中。

    shell

    如果shell是True,则将通过shell执行指定的命令。如果你使用Python主要是由于它能提供大多数系统shell不能提供的增强的控制流,并且仍然希望方便地访问其他shell功能,如shell管道、文件名通配符、环境变量扩展和扩展〜到用户的主目录,这会很有用。

    >>> 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(环境变量)

    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
    
    
    关注公众号 海量干货等你
  • 相关阅读:
    hdu 5446 Unknown Treasure lucas和CRT
    Hdu 5444 Elven Postman dfs
    hdu 5443 The Water Problem 线段树
    hdu 5442 Favorite Donut 后缀数组
    hdu 5441 Travel 离线带权并查集
    hdu 5438 Ponds 拓扑排序
    hdu 5437 Alisha’s Party 优先队列
    HDU 5433 Xiao Ming climbing dp
    hdu 5432 Pyramid Split 二分
    Codeforces Round #319 (Div. 1) B. Invariance of Tree 构造
  • 原文地址:https://www.cnblogs.com/sowhat1412/p/12734311.html
Copyright © 2011-2022 走看看