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

92 次浏览16 条回复

有些小脚本要调外部命令,直接 subprocess.run() 也行,但命令不存在时错误会绕一点。先用 shutil.which() 看一眼,提示能清楚些。

环境:Python 3.10+,只用标准库。保存为 which-demo.py

import shutil
import subprocess

cmd = shutil.which('python')

if cmd is None:
    raise SystemExit('找不到 python 命令')

result = subprocess.run([cmd, '-V'], check=True, capture_output=True, text=True)
print(result.stdout.strip() or result.stderr.strip())

这种适合写给别人跑的小工具。缺依赖时早点报明白,比后面栈一大截舒服。

这个挺实用。补一句,Windows 上有时 python 不一定在 PATH 里,但 py 可能在;shutil.which() 先探一下,报错会更直。小脚本里我也会顺手把实际找到的路径打出来,排查环境挺省事。

这个点挺实用。顺手再补一句,Windows 上有时 python 不在 PATH 里,但 py 可能在;先 which 一下,报错会直很多。要是把找到的实际路径也打出来,排环境会省心一点。

我一般还会顺手看一下 sys.executable

入口命令用 shutil.which() 探,子进程真要跟着当前环境跑的时候,用当前解释器更稳一点。这样排环境时,少猜一层。

补一个小坑:shutil.which() 只看 PATH,不看 shell 里的 alias / 函数。要是你本地能跑、脚本里却找不到,很多时候就是这个原因。脚本里拿到绝对路径再喂给 subprocess.run(),会省一点玄学。

我一般会把 shutil.which() 找到的实际路径也打出来,像 找到的是: /usr/bin/python3 这种。

PATH 里有多个 Python 的时候,这一行挺救命的,至少一眼能看出脚本最后到底用了谁。

我一般会再给它留几个候选名,python3pythonpy 轮着试一下。

有时候不是脚本写错,是环境里名字不一样;这种小兜底挺省心。

再补个小细节:如果脚本是给别人跑的,失败时把当前 PATH 里相关那段也带出来,会比单写一句‘找不到命令’好排很多。环境一乱,光看报错名经常不够。

如果后面是要再起一个 Python 进程,我会更偏向直接用 sys.executable。这样子进程跟当前解释器是一套,少踩虚拟环境里多个 Python 混在一起的坑。shutil.which() 更适合拿来做命令存在性检查。

HosuLv1#8

如果后面是要再起一个 Python 进程,我会更偏向直接用 sys.executable。这样子进程跟当前解释器是一套,少踩虚拟环境里多个 Python 混在一起的坑。shutil.which() 更适合拿来做命令存在性检查。

再补个小细节:如果你想让脚本更稳一点,最好别只把 python 写死。像 python3pythonpy 轮一圈,拿到第一个可用的再跑,实际环境里会少很多‘本机能跑、别人机器不行’的情况。

shutil.which() 放在这一步就挺合适,报错也会更直白。

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