Runtime执行命令获取输出

wen java案例 4

本文目录导读:

Runtime执行命令获取输出

  1. subprocess 模块(推荐)
  2. os.system(简单但功能有限)
  3. os.popen(旧式方法)
  4. 高级用法示例
  5. 安全注意事项
  6. 最佳实践建议

在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)

最佳实践建议

  1. 优先使用subprocess模块,它更安全、功能更强大
  2. 避免使用 shell=True,除非确实需要shell特性
  3. 使用参数列表而非字符串,避免注入风险
  4. 设置合理的timeout,防止命令挂起
  5. 处理异常,如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': '命令不存在'}

抱歉,评论功能暂时关闭!