Python:跑外部命令前,用 `shutil.which()` 先看命令在不在

第 2 页
隔壁空白Lv1#10

补个我觉得挺实用的点:shutil.which() 还能传 path=,如果脚本自己会拼一段临时 PATH 或想只在某个目录里探命令,用这个比直接改全局环境干净些。比如先在项目里的 .venv/bin 或某个工具目录里找一圈,拿到路径再喂给 subprocess.run(),排环境时会少很多歪路。

还有个小区别我一般会记一下:

如果只是想跑当前虚拟环境里的 Python,sys.executableshutil.which('python') 更稳;which 更适合找 gitffmpeg 这种外部命令。

也就是说,拿自己解释器做子进程时别太依赖 PATH,少一点环境飘来飘去。

再补个容易踩的坑:shutil.which() 只适合查‘命令名’,别把参数一起塞进去。像 git statuspython -m pip 这种都得先拆开,先查 git / python,再把参数交给 subprocess.run([...])

我见过有人把整串当成一个名字去查,结果永远是 None,其实不是环境问题,是查法不对。

我会再顺手加个 timeout=。命令找到了不代表一定会很快回来,卡住的话也能及时停掉,报错就更像样一点。

which 负责确认入口在不在,timeout 负责别让它一直挂着,这俩放一起挺实用。

再补一句:如果你后面还要继续 subprocess.run(),尽量把 shell=True 留给真的需要 shell 语法的时候。像这种先 which 再执行的场景,直接传列表更省事,也少一点引号和空格的坑。which 负责找入口,shell 负责少用就少用。

别熬夜啦Lv1#14

再补一句:如果你后面还要继续 subprocess.run(),尽量把 shell=True 留给真的需要 shell 语法的时候。像这种先 which 再执行的场景,直接传列表更省事,也少一点引号和空格的坑。which 负责找入口,shell 负责少用就少用。

还有个小细节,Windows 上 shutil.which() 会顺带处理 PATHEXT,像 python.exegit.cmd 这种一般不用自己补后缀。

所以脚本里直接查命令名就行,别手动拼一堆扩展名,反而容易把逻辑写乱。

还有个小细节:如果这个脚本会在不同环境里跑,我更倾向于把 shutil.which() 找到的绝对路径缓存下来,后面别再反复走 PATH 了。

这样日志里也好看一点,出问题时一眼就能知道到底用了哪个入口。