Skip to content

36|系统交互

Python 脚本经常需要与操作系统交互:执行系统命令、读取环境变量、处理命令行参数、操作进程。标准库的 subprocessossysargparse 提供了这些能力。

一、执行系统命令

subprocess.run() 是执行外部命令的推荐方式:

python
import subprocess

result = subprocess.run(
    ["ls", "-la"],           # 命令和参数用列表传
    capture_output=True,     # 捕获 stdout 和 stderr
    text=True,               # 输出按文本处理(不是 bytes)
    check=False,             # 非零退出码不自动抛异常
)

print(result.returncode)    # 0 表示成功
print(result.stdout)        # 标准输出
print(result.stderr)        # 标准错误

capture_output=True 等价于 stdout=subprocess.PIPE, stderr=subprocess.PIPE

安全警告:不要拼字符串传命令,尤其当命令包含外部输入时:

python
# 危险:命令注入
filename = "; rm -rf /"   # 假设来自用户输入
subprocess.run(f"cat {filename}", shell=True)
# Shell 会把这一行解析成:cat ; rm -rf /

# 安全:列表传参
subprocess.run(["cat", filename])
# filename 只是一个字符串参数,不会被当命令执行

shell=True 把字符串交给 Shell 解释器解析,有命令注入风险。除非必须使用 Shell 特性(如管道、重定向、通配符),否则不要用 shell=True

需要 Shell 特性时,用列表传基础命令,Python 处理逻辑:

python
# 不用 shell=True 的管道
p1 = subprocess.Popen(["cat", "data.txt"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "error"], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
output = p2.communicate()[0]

二、环境变量

python
import os

# 读取
env = os.environ.get("APP_ENV", "dev")     # 没设置时返回默认值 "dev"
api_url = os.environ.get("API_URL")         # 没设置时返回 None

# 必填变量集中校验
def require_env(name):
    value = os.environ.get(name)
    if not value:
        raise RuntimeError(f"缺少环境变量: {name}")
    return value

token = require_env("API_TOKEN")

密码、Token 等敏感信息不要硬编码在代码里。环境变量、配置文件(权限收紧)、密钥管理系统都比硬编码可控。

三、命令行参数

argparse 解析命令行参数,自动生成帮助信息:

python
import argparse

def parse_args():
    parser = argparse.ArgumentParser(description="处理数据文件")
    parser.add_argument("input", help="输入文件路径")
    parser.add_argument("-o", "--output", default="output.txt", help="输出文件路径")
    parser.add_argument("-v", "--verbose", action="store_true", help="详细输出")
    parser.add_argument("-n", "--count", type=int, default=1, help="处理次数")
    return parser.parse_args()

args = parse_args()
print(args.input)     # 位置参数
print(args.output)    # 可选参数,默认值 output.txt
print(args.verbose)   # True 或 False
print(args.count)     # 整数,默认 1

运行:

bash
python script.py input.txt -o result.txt -v -n 5
python script.py --help   # 自动生成帮助

四、进程信息

python
import os

os.getpid()       # 当前进程 ID
os.getppid()      # 父进程 ID
os.getcwd()       # 当前工作目录
os.chdir("/tmp")  # 切换目录

五、临时文件

python
import tempfile

# 创建临时文件
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
    f.write("临时数据")
    print(f.name)   # 临时文件路径

# 创建临时目录
with tempfile.TemporaryDirectory() as tmpdir:
    print(tmpdir)   # 临时目录路径
    # 在 tmpdir 中操作...
# 离开 with 块后自动删除

delete=False 表示退出 with 块后不自动删除,方便排查。默认 delete=True

六、锁文件

防止同一个脚本重复运行:

python
from pathlib import Path
import os

lock_path = Path("/tmp/my_script.lock")

if lock_path.exists():
    raise SystemExit(f"锁文件存在: {lock_path}")

try:
    lock_path.write_text(str(os.getpid()))
    print("执行主逻辑")
finally:
    lock_path.unlink(missing_ok=True)

这种锁文件适合单机简单场景。跨机器、长任务、异常退出后自动清理这些需求,要换分布式锁或调度系统。

记忆锚点subprocess.run() 执行命令,列表传参安全,shell=True 有注入风险;环境变量用 os.environ.get() 读取;argparse 解析命令行参数;敏感信息从环境变量读,不要硬编码;tempfile 创建临时文件/目录;锁文件防止重复运行,单机简单场景够用。