subprocess 模块,子进程管理(Subprocess management),用于生成新进程,连接到它们的输入/输出/错误管道,并得到它们的返回代码. 其意在取代旧的模块,如 os.systemos.spawn*.

通用场景,推荐采用 subprocess.run() 函数来调用子进程.

更高级应用场景,推荐采用 subprocess.Popen 接口.

中文文档:https://docs.python.org/zh-cn/3/library/subprocess.html#

英文文档:https://docs.python.org/3/library/subprocess.html

1. subprocess.run

1.1. 定义

函数定义如:

subprocess.run(args, *, 
               stdin=None, 
               input=None, 
               stdout=None, 
               stderr=None, 
               capture_output=False, 
               shell=False,  #若True,则采用操作系统的 shell 执行命令
               cwd=None, 
               timeout=None,  #超时时间
               check=False, 
               encoding=None, #编码格式
               errors=None, 
               text=None, 
               env=None, 
               universal_newlines=None, 
               **other_popen_kwargs)

函数功能为,通过参数 args 运行命令,当执行完毕后,返回一个 CompletedProcess 实例.

[1] - capture_output=True 则捕获 stdoutstderr

1.2. 示例

run 方法和直接用 Popen 差不多,实现一样,其实际上也是调用 Popen.

import subprocess

#执行 ls -lh /home
subprocess.run(["ls", "-lh", "/home"])
#输出:
#   CompletedProcess(args=['ls', '-lh', '/home'], returncode=0)

subprocess.run(["ls", "-l", "/dev/null"], capture_output=True)

再如,

import subprocess

def cmd(command):
    ret = subprocess.run(command,
                         shell=True,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         encoding="utf-8",
                         timeout=1)
    if ret.returncode == 0:
        print("success:",ret)
    else:
        print("error:",ret)

#
cmd(["dir","/home"]) #序列参数
cmd(["nvidia-smi"])
cmd("exit 1")        #字符串参数

2. subprocess.CompletedProcess

CompletedProcesssubprocess.run() 的返回值,表示一个进程已经完成.

其包含:

[1] - args: 启动进程的参数,可以是 list 或 str.

[2] - returncode: 子进程的退出状态. 一般情况下,退出状态为 0 表示成功运行; 退出状态为-N表示子进程被信号 N 终止.

[3] - stdout: 捕获子进程的 stdout. 一般为字节或字符串;如值为 None 则表示没有捕获到 stdout.

[4] - stderr: 捕获子进程的 stderr.

[5] - check_returncode(): 若 returncode 值为非零,则返回 CalledProcessError.

3. subprocess.Popen

Popen 函数是 subprocess 的核心,在新进程运行子程序. 处理子进程的创建和管理.

3.1. 定义

函数定义如:

class subprocess.Popen(args, 
                       bufsize=-1, #缓冲区大小;0-不使用缓冲区;1-行缓冲;
                       executable=None, 
                       stdin=None, 
                       stdout=None, 
                       stderr=None, 
                       preexec_fn=None, 
                       close_fds=True, 
                       shell=False, 
                       cwd=None, #设置子进程的当前目录
                       env=None, 
                       universal_newlines=None, 
                       startupinfo=None, 
                       creationflags=0, 
                       restore_signals=True, 
                       start_new_session=False, 
                       pass_fds=(), 
                       *, 
                       group=None, 
                       extra_groups=None, 
                       user=None, 
                       umask=-1, 
                       encoding=None, 
                       errors=None, 
                       text=None)

参考 suprocess.run 方法.

3.2. 示例

import subprocess

pn = subprocess.Popen('ls -lh', shell=True)
#或:
#pn = subprocess.Popen(['ls', '-lh'])
pn.returncode
pn.wait()
pn.returncode

pn = subprocess.Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])
#subprocess.Popen(['/bin/sh', '-c', args[0], args[1], ...])

3.3. 对象方法

3.3.1. Popen.poll()

检查子进程是否结束. 正常返回是 returncode; 否则返回 None.

3.3.2. Popen.wait(timeout=None)

等待子进程终止.

3.3.3. Popen.communicate(input, timeout)

和子进程交互,发送和读取数据.

返回值为元组 (stdout_data, stderr_data).

3.3.4. Popen.send_signal(signal)

发送信号到子进程.

3.3.5. Popen.terminate()

停止子进程.

3.3.6. Popen.kill()

杀掉子进程.

3.4. 示例

import time
import subprocess

def cmd(command):
    subpn = subprocess.Popen(command,
                            shell=True,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE,
                            encoding="utf-8")
    subpn.wait(2)
    print(subpn.poll())
    if subpn.poll() == 0:
        print(subpn.communicate()[1])
    else:
        print("Failed")

#
cmd("nvcc --version")
cmd("exit 1")
Last modification:January 12th, 2022 at 03:13 pm