subprocess 模块允许你生成新的进程,连接它们的输入、输出、错误管道,并且获取它们的返回码。此模块可以代替一些老旧的模块与功能,如os.system, os.spawn, os.popen()等。

Old Version Review

import os

# 执行命令行命令
os.popen('ls').read().split()
# ['data', 'preprocessing.ipynb', 'test.ipynb']

os.system('ls') # 只返回执行的退出状态
# 0

Better yet, you can use subprocess, it is safer, more powerful and likely faster.

subprocess.run

subprocess.run是在python3.5中新加入的方法,是subprocess.Popen的简化版。

subprocess.run运行一个命令并等待命令结束返回结果,可以看做是自动调用Popencommunicate

语法:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)

例子:

import subprocess

result1 = subprocess.run('echo "I like python"', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # invoking shell
result2 = subprocess.run(['echo', 'I like potatos'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # without invoking shell

print(result1)
print(result2)

# output
CompletedProcess(args='echo "I like python"', returncode=0, stdout=b'I like python\n', stderr=b'')
CompletedProcess(args=['echo', 'I like potatos'], returncode=0, stdout=b'I like potatos\n', stderr=b'')
print(result2.returncode)
print(result2.stdout)
print(result2.stderr)

# output
0
b'I like potatos\n'
b''

参数说明:

第一个参数是args,可以是一个字符串也可以是一个参数序列(列表),如果是字符串shell参数应该设置为True,表示调用shell执行该shell命令。更加推荐使用参数序列赋值。

stdinstdoutstderr 分别指定了执行的程序的标准输入、输出和标准错误文件句柄。 PIPE 表示新建一个对子进程的管道。

import subprocess

completed = subprocess.run(['ls', '-1'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print('returncode:', completed.returncode)
print(f"结果的字节长度 {len(completed.stdout)}:\n{completed.stdout.decode('utf-8')}")

"""
returncode: 0
结果的字节长度 65:
classification.ipynb
hyperopt_output
regression.ipynb
test.ipynb
"""

错误处理

import subprocess
try:
    subprocess.run(['false'], check=True)
except subprocess.CalledProcessError as err:
    print('ERROR:', err)
    
# ERROR: Command '['false']' returned non-zero exit status 1.

false 命令总是以非零状态代码退出,run()将其解释为错误。 将 run()函数的 check 属性设置为 True,等同于使用check_returncode()方法。

subprocess.Popen

Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。一般场景下用run方法就可以了,Popen更加底层,灵活性更高。

语法:

class subprocess.Popen(args, bufsize=-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=(), *, encoding=None, errors=None, text=None)
import subprocess

result = subprocess.Popen(['echo', 'I like potatos'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)  
# without invoking shell
print(result)
# <subprocess.Popen object at 0x10e6df7f0>
out, err = result.communicate()
print(out, err)
# b'I like potatos\n' b''
print(f"STDOUT: {out.decode('ascii')}STDERR: {err.decode('ascii')}")
# STDOUT: I like potatos
# STDERR:

REFERENCE

subprocess

subprocess-example

Python 调用系统命令的模块 Subprocess