跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Python异步环境下怎么执行Shell命令_使用create_subprocess_exec

asyncio.create_subprocess_exec() 不能直接传字符串命令,因为它直连 execve 系统调用、不经过 shell 解析,必须传入程序名与分离参数列表(如 ["ls", "-l"]),否则会因找不到名为 "ls -l" 的可执行文件而报 FileNotFoundError。 asyncio.create_subprocess_exec() 为什么不能直接传字符串命令 因为
create_subprocess_exec()
是“直连操作系统 execve 系统调用”的封装,它不经过 shell 解析器。你传进去的必须是可执行程序名 + 分离的参数列表,比如
["ls", "-l", "/tmp"]
,而不是
"ls -l /tmp"
。传字符串会报
FileNotFoundError: [Errno 2] No such file or directory
——它试图找一个叫
"ls -l /tmp"
的可执行文件,当然不存在。 常见错误现象: 误写成
await asyncio.create_subprocess_exec("ping -c 1 google.com")
→ 报错 在 Windows 上传路径含空格但没加引号(如
["C:\Program Files\nodejs\node.exe", "--version"]
)→ 找不到文件 正确做法是手动拆解命令:
proc = await asyncio.create_subprocess_exec( "ping", "-c", "1", "google.com", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE )
如果真需要 shell 功能(通配符、管道、变量展开),该用
create_subprocess_shell()
,而不是硬塞字符串进
exec
。 立即学习 “ Python免费学习笔记(深入) ”; stdin/stdout/stderr 参数怎么配才不卡死 默认情况下,
stdin
/
stdout
/
stderr
都是
None
,即继承父进程的对应流(通常是终端)。这在后台异步任务里极易导致阻塞或不可控输出。要捕获输出,必须显式设为
asyncio.subprocess.PIPE
;要避免子进程因 stdin 未关闭而挂起,通常得设
stdin=asyncio.subprocess.DEVNULL
或主动
proc.stdin.close()
。 关键点: 只要用了
PIPE
,就必须调用
proc.communicate()
(或分别读
stdout.read()
+
stderr.read()
),否则子进程可能永远等不到 EOF
limit
参数控制缓冲区大小(默认 64KiB),大输出(如
tar -cz
)不设容易内存爆掉 不要混用
proc.stdout.readline()
和
proc.communicate()
,前者会消费缓冲区,后者会再读一次,导致丢数据或 hang 示例(安全捕获): Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载
proc = await asyncio.create_subprocess_exec(
    "find", "/", "-name", "*.py", "-print0",
    stdout=asyncio.subprocess.PIPE,
    stderr=asyncio.subprocess.DEVNULL,
    limit=1024*1024  # 1MB 缓冲
)
stdout, _ = await proc.communicate()
和 subprocess.run() 的核心区别在哪 最根本的是:前者是异步非阻塞,后者是同步阻塞。你在协程里用
subprocess.run(),整个事件循环就停了,哪怕只等 1 秒,所有其他任务(网络请求、定时器、UI 更新)全卡住。
性能与场景差异: 并发多个命令?
create_subprocess_exec()
+
asyncio.gather()
天然支持;
run()
只能串行或开线程池(额外管理开销) 需要实时流式处理输出(如 tail -f 日志)?只有
exec
能边读边处理;
run()
必须等命令结束才拿到全部 stdout 超时控制更精细:
proc.wait()
可以配合
asyncio.wait_for()
做细粒度 timeout;
run(timeout=...)
是粗暴 kill 别被“简单”误导:用
run()
写脚本没问题,但在 FastAPI/Quart/ASGI 应用或长周期监控服务里混用,就是隐性性能地雷。 Windows 下路径和编码问题怎么绕过去 Windows 的 cmd/powershell 默认编码不是 UTF-8,且路径分隔符、空格、驱动器盘符都容易出事。这不是 asyncio 的锅,但会集中暴露在
create_subprocess_exec()
场景里。 实操建议: 避免依赖系统 shell 工具,优先用 Python 内置模块(
shutil.copytree
替代
xcopy
) 调用外部程序时,用绝对路径并确保路径中无中文或特殊字符;含空格路径必须作为独立参数传,不要拼接 如果必须处理中文路径或输出,显式指定
encoding="utf-8"
在
proc.stdout.decode()
里,别依赖系统 locale PowerShell 命令一律走
create_subprocess_shell()
,并加
-ExecutionPolicy Bypass -Command
前缀,
exec
不认 PowerShell 语法 容易被忽略的一点:Windows 上某些程序(如
robocopy
)退出码语义和 Unix 完全不同,
proc.returncode == 0
不一定代表成功,得查文档看具体含义。

相关文章