本文目录导读:

在Python中,有几种方式可以在运行时执行系统命令并获取输出,这里介绍最常用的几种方法:
subprocess 模块(推荐)
基础用法
import subprocess
# 获取命令输出
result = subprocess.run(['ls', '-la'], capture_output=True, text=True)
print(result.stdout) # 标准输出
print(result.stderr) # 错误输出
# 检查返回值
if result.returncode == 0:
print("命令执行成功")
常用参数说明
# 设置工作目录
result = subprocess.run(['ls'], cwd='/tmp', capture_output=True, text=True)
# 设置超时时间
try:
result = subprocess.run(['sleep', '5'], timeout=3)
except subprocess.TimeoutExpired:
print("命令超时")
# 实时获取输出
process = subprocess.Popen(['ping', '8.8.8.8'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
for line in process.stdout:
print(line.strip()) # 实时打印输出
# 获取完整输出
stdout, stderr = process.communicate(timeout=10)
print(f"完整输出: {stdout}")
os.system(简单但功能有限)
import os
# 执行命令,只返回退出状态码
return_code = os.system('ls -la')
print(f"退出码: {return_code}")
# 无法直接获取输出,但可以重定向
os.system('ls -la > output.txt')
os.popen(旧式方法)
import os
# 读取输出
with os.popen('ls -la') as f:
output = f.read()
print(output)
# 写入命令输入
with os.popen('wc -l', 'w') as f:
f.write('line1\nline2\nline3\n')
高级用法示例
管道命令
import subprocess
# 链式命令(等同于 ls | grep .py)
ps1 = subprocess.Popen(['ls'], stdout=subprocess.PIPE)
ps2 = subprocess.Popen(['grep', '.py'], stdin=ps1.stdout,
stdout=subprocess.PIPE, text=True)
ps1.stdout.close() # 允许ps1在ps2运行时接收SIGPIPE信号
output = ps2.communicate()[0]
print(f"Python文件: {output}")
带环境变量
import subprocess import os env = os.environ.copy() env['MY_VAR'] = 'custom_value' result = subprocess.run(['env'], env=env, capture_output=True, text=True) print(result.stdout)
同时处理stdout和stderr
import subprocess
# 合并stdout和stderr
result = subprocess.run(['ls', '/nonexistent'],
capture_output=True,
text=True,
stderr=subprocess.STDOUT)
print(f"合并的输出: {result.stdout}")
# 分别处理
result = subprocess.run(['ls', '/nonexistent'],
capture_output=True,
text=True)
print(f"stdout: {result.stdout}")
print(f"stderr: {result.stderr}")
安全注意事项
import subprocess
import shlex
# ❌ 危险:直接使用shell=True可能导致注入
user_input = "; rm -rf /"
result = subprocess.run(f"echo {user_input}", shell=True, capture_output=True, text=True)
# ✅ 安全:使用参数列表
result = subprocess.run(['echo', user_input], capture_output=True, text=True)
# ✅ 或者使用shlex.quote
safe_input = shlex.quote(user_input)
result = subprocess.run(f"echo {safe_input}", shell=True, capture_output=True, text=True)
最佳实践建议
- 优先使用subprocess模块,它更安全、功能更强大
- 避免使用 shell=True,除非确实需要shell特性
- 使用参数列表而非字符串,避免注入风险
- 设置合理的timeout,防止命令挂起
- 处理异常,如FileNotFoundError、TimeoutExpired等
import subprocess
def run_command(cmd, timeout=30):
"""安全的命令执行封装"""
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout,
check=True # 非零返回码会抛出CalledProcessError
)
return {
'success': True,
'stdout': result.stdout,
'stderr': result.stderr,
'returncode': result.returncode
}
except subprocess.TimeoutExpired:
return {'success': False, 'error': '命令执行超时'}
except subprocess.CalledProcessError as e:
return {'success': False, 'error': f'命令返回错误码 {e.returncode}', 'output': e.output}
except FileNotFoundError:
return {'success': False, 'error': '命令不存在'}