subprocess 模块是 Python 中用于创建和管理子进程的标准库模块,它允许你启动新的应用程序、连接到它们的输入/输出/错误管道,并获取它们的返回码。
基本用法 #
1. 运行简单命令 #
最简单的用法是使用 subprocess.run() 函数:
import subprocess
# 运行简单命令
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)2. 替代旧的模块方法 #
subprocess 模块旨在替代以下旧模块和函数:
os.system()os.spawn*()os.popen()popen2.*()commands.*()
主要函数 #
subprocess.run() #
最常用的高级接口,Python 3.5+ 推荐使用:
result = subprocess.run(
args, # 命令字符串或列表
*,
stdin=None, # 标准输入
input=None, # 传递给子进程的数据
stdout=None, # 标准输出处理
stderr=None, # 标准错误处理
capture_output=False, # 是否捕获输出
shell=False, # 是否通过shell执行
cwd=None, # 工作目录
timeout=None, # 超时时间
check=False, # 如果非零退出码是否抛出异常
text=None, # 是否以文本模式处理输入输出
encoding=None, # 编码
errors=None # 编码错误处理方式
)subprocess.Popen() #
更底层的接口,提供更多控制:
proc = 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=(),
*,
group=None,
extra_groups=None,
user=None,
umask=-1,
encoding=None,
errors=None,
text=None
)常见用法示例 #
1. 捕获命令输出 #
result = subprocess.run(['echo', 'Hello World'], capture_output=True, text=True)
print(result.stdout) # 输出: Hello World\n2. 检查命令是否成功 #
try:
subprocess.run(['false'], check=True)
except subprocess.CalledProcessError as e:
print(f"命令失败,返回码: {e.returncode}")3. 使用管道 #
# 将前一个命令的输出作为下一个命令的输入
p1 = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['grep', 'py'], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close() # 允许p1收到SIGPIPE如果p2退出
output = p2.communicate()[0]
print(output.decode('utf-8'))4. 设置超时 #
try:
subprocess.run(['sleep', '10'], timeout=5)
except subprocess.TimeoutExpired:
print("命令执行超时")5. 使用 shell 特性 #
# 使用shell执行复杂命令
subprocess.run('ls -l | grep py', shell=True)6. 设置环境变量 #
env = {'PATH': '/usr/local/bin:' + os.environ['PATH']}
subprocess.run(['my_command'], env=env)安全注意事项 #
避免使用
shell=True:除非必要,否则应避免使用,因为它可能存在 shell 注入风险。# 不安全 subprocess.run(f'ls {user_input}', shell=True) # 更安全的方式 subprocess.run(['ls', user_input])正确处理输入:当处理用户输入时,应始终进行适当的清理和验证。
高级特性 #
1. 实时处理输出 #
proc = subprocess.Popen(['ping', 'google.com'], stdout=subprocess.PIPE)
while True:
line = proc.stdout.readline()
if not line:
break
print(line.decode('utf-8').strip())2. 同时处理 stdout 和 stderr #
proc = subprocess.Popen(['command'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
stdout, stderr = proc.communicate()3. 交互式进程 #
proc = subprocess.Popen(['python'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True)
proc.stdin.write("print('Hello')\n")
proc.stdin.flush()
output = proc.stdout.readline()
print(output) # 输出: Hello总结 #
subprocess 模块提供了强大而灵活的方式来与系统命令和外部程序交互。对于大多数用例,subprocess.run() 是首选的高级接口,而 Popen 则提供了更底层的控制。始终注意安全性,特别是在处理用户输入时。