python subprocess模块基本使用。

run

如果仅仅是为了运行一个外部命令而不用交互,类似 os.system(),可以使用 run() 方法。

completed = subprocess.run(['ls', '-l'])
print('returncode:', completed.returncode)

run方法返回一个CompletedProcess实例,包含进程退出码以及输出等信息。

设置shell参数为True会导致subprocess创建一个新的中间shell进程运行命令。默认的行为是直接运行命令:

completed = subprocess.run('echo $HOME', shell=True)
print('returncode:', completed.returncode)

如果需要使用shell管道、文件通配符、环境变量展开以及 ~ 展开到用户家目录,这将非常有用。

错误处理

CompletedProcess 的 returncode 属性是程序的退出码。调用者负责解释它并检测错误。如果 run() 的 check 参数是 True,退出码将会被检查,如果有错误出现将会引发 CalledProcessError 异常。

try:
    subprocess.run(['false'], check=True)
except subprocess.CalledProcessError as err:
    print('ERROR:', err)

捕获输出

由 run() 启动的进程的标准输入输出渠道绑定在了父进程上。那就意味着调用程序不能捕获命令的输出。给 stdout 和 stderr 参数传递 PIPE 可以捕获输出用于后续处理。

completed = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
print('returncode:', completed.returncode)
print('Have {} bytes in stdout:\n{}'.format(len(completed.stdout), completed.stdout.decode('utf-8')))

上面的也可以直接用check_output()方法获得标准输出:

completed = subprocess.check_output(['ls', '-l'])
print(completed.decode('utf-8'))

默认情况下,check_output() 仅仅返回输入到标准输出的值。如果你需要同时收集标准输出和错误输出,使用 stderr 参数:

completed = subprocess.check_output(['ls', '-l'], stderr=subprocess.STDOUT)

这个方法特别好用。

抑制输出

某些情况下,输出不应该被展示和捕获,使用 DEVNULL 抑制输出流。

import subprocess

try:
    completed = subprocess.run(
        'echo to stdout; echo to stderr 1>&2; exit 1',
        shell=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )
except subprocess.CalledProcessError as err:
    print('ERROR:', err)
else:
    print('returncode:', completed.returncode)
    print('stdout is {!r}'.format(completed.stdout))
    print('stderr is {!r}'.format(completed.stderr))
$python3 sub.py
returncode: 1
stdout is None
stderr is None
  • !s 在参数值上调用 str()
  • !r 在参数值上调用 repr()

popen方法

函数 run() ,call() ,check_call() 和 check_output() 是 Popen 类的包装。直接使用 Popen 能够对如何运行命令以及如何处理输入输出流提供更多的控制。

text = b'''
    hello world
    this is a test
    goodbye'''

p = subprocess.Popen(['wc',], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
stdout, stderr = p.communicate(text)
out = stdout.decode('utf-8')
print(out)