ffmpeg 不是内部或外部命令:先查 PATH
一个不装依赖的 Node 脚本,检查 ffmpeg 和 ffprobe 是否在 PATH 里、常见安装目录有没有文件,并按 Windows、macOS、Linux 给出下一步。
本页目录
30 秒速查
- 先跑
node check-ffmpeg.mjs,看是「没装」还是「没进 PATH」- 没装:Windows 解压到
C:\ffmpeg;macOSbrew install ffmpeg- 装了找不到:把
bin目录加进 PATH,重开终端- 验证:
ffmpeg -version和ffprobe -version
先别急着重装
装完 ffmpeg,终端还是回你「不是内部或外部命令」。重装通常没用:问题往往不在 ffmpeg,而在 PATH。
终端不搜整个硬盘,只按 PATH 里的目录逐个找。ffmpeg 装了,但 bin 目录不在 PATH 里,终端就当作没装。
先分清三种情况,再动手:
| 现象 | 原因 | 先做什么 |
|---|---|---|
| 从没装过 | 系统里没有 ffmpeg | 安装 |
| 装过,但提示找不到 | bin 目录没进 PATH |
加 PATH |
| 加过 PATH,还是找不到 | 终端没重开、改错了用户变量,或只改了当前会话 | 重开终端再查 |
从没装过 → 安装
系统里没有 ffmpeg,按自己的系统装一次完整版。
装过但找不到 → 加 PATH
bin 目录没进 PATH,终端就当作没装。
加过还找不到 → 重开终端
终端没重开、改错用户变量,或只改了当前会话。
报错长什么样
不同终端的说法不一样,意思相同:在 PATH 里没找到这个命令。
Windows 的 cmd:
'ffmpeg' 不是内部或外部命令,也不是可运行的程序或批处理文件。
Windows 的 PowerShell 会啰嗦一些,开头是:
ffmpeg : 无法将“ffmpeg”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
macOS 的 zsh:
zsh: command not found: ffmpeg
Linux 的 bash:
bash: ffmpeg: command not found
看到这些,不要先怀疑安装包坏了。先确认文件到底在不在,以及它在不在 PATH 里。
跑一次检查
新建 check-ffmpeg.mjs,把下面整段复制进去。它只用 Node 自带模块,不装依赖:
import { existsSync } from "node:fs";
import path from "node:path";
import { spawnSync } from "node:child_process";
import { pathToFileURL } from "node:url";
const HINTS = {
darwin: "macOS:brew install ffmpeg",
win32: "Windows:从 ffmpeg.org 下载构建包,解压后把 bin 目录加进用户 PATH",
linux: "Linux:sudo apt install ffmpeg(Debian/Ubuntu)或 sudo dnf install ffmpeg(Fedora)",
};
export function hintFor(platform = process.platform) {
return HINTS[platform] ?? HINTS.linux;
}
export function commonPaths(platform = process.platform, env = process.env) {
if (platform === "win32") {
const home = env.USERPROFILE ?? "C:\\Users\\你";
const local = env.LOCALAPPDATA ?? path.win32.join(home, "AppData", "Local");
return [
"C:\\ffmpeg\\bin\\ffmpeg.exe",
"C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe",
"C:\\ProgramData\\chocolatey\\bin\\ffmpeg.exe",
path.win32.join(home, "scoop", "shims", "ffmpeg.exe"),
path.win32.join(local, "Microsoft", "WinGet", "Links", "ffmpeg.exe"),
];
}
if (platform === "darwin") {
return ["/opt/homebrew/bin/ffmpeg", "/usr/local/bin/ffmpeg", "/opt/local/bin/ffmpeg"];
}
return ["/usr/bin/ffmpeg", "/usr/local/bin/ffmpeg", "/snap/bin/ffmpeg"];
}
export function pathEntries(env = process.env, platform = process.platform) {
const raw = env.PATH ?? env.Path ?? "";
return raw.split(platform === "win32" ? ";" : ":").filter(Boolean);
}
export function findInPath(command, { platform = process.platform, env = process.env, exists = existsSync } = {}) {
const names = platform === "win32" ? [`${command}.exe`, command] : [command];
for (const dir of pathEntries(env, platform)) {
for (const name of names) {
const file = platform === "win32" ? path.win32.join(dir, name) : path.join(dir, name);
if (exists(file)) return file;
}
}
return null;
}
export function parseVersion(output, tool = "ffmpeg") {
const match = new RegExp(`^${tool} version (\\S+)`, "m").exec(output);
return match ? match[1] : null;
}
function probeCommand(tool) {
const result = spawnSync(tool, ["-version"], { encoding: "utf8" });
if (result.error || result.status !== 0) return { found: false };
const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`;
return { found: true, version: parseVersion(output, tool) };
}
export function diagnose(options = {}) {
const {
platform = process.platform,
env = process.env,
exists = existsSync,
probe = probeCommand,
} = options;
return {
platform,
ffmpeg: probe("ffmpeg"),
ffprobe: probe("ffprobe"),
candidates: commonPaths(platform, env).map((file) => ({ file, exists: exists(file) })),
};
}
function printReport({ platform, ffmpeg, ffprobe, candidates }) {
const status = (item) => (item.found ? (item.version ?? "已安装(版本未知)") : "未找到");
console.log(`ffmpeg:${status(ffmpeg)}`);
console.log(`ffprobe:${status(ffprobe)}`);
if (ffmpeg.found) {
const file = findInPath("ffmpeg", { platform });
if (file) console.log(`路径:${file}`);
}
if (ffmpeg.found && ffprobe.found) {
console.log("\n状态:可用,视频脚本可以继续。");
return;
}
if (ffmpeg.found && !ffprobe.found) {
console.log("\nffprobe 缺失。它通常和 ffmpeg 在同一个安装包里,重装完整版本即可。");
console.log("装完重开终端,再运行 ffprobe -version 确认。");
return;
}
console.log("\n常见安装位置:");
for (const item of candidates) {
console.log(` ${item.exists ? "存在 " : "不存在"} ${item.file}`);
}
const installed = candidates.filter((item) => item.exists);
console.log("\n怎么处理:");
if (installed.length > 0) {
console.log(` 已经找到了文件,但它不在 PATH 里:${installed[0].file}`);
console.log(" 把它的 bin 目录加进 PATH,重开终端后再运行一次这个脚本。");
} else {
console.log(` ${hintFor(platform)}`);
}
console.log(" 装完先关掉终端再重开,然后运行 ffmpeg -version 确认。");
}
const isDirectRun =
process.argv[1] &&
pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url;
if (isDirectRun) {
printReport(diagnose());
}
代码只做三件事:
- 分别运行
ffmpeg -version和ffprobe -version。找不到时spawnSync返回ENOENT,不会把终端搞崩。 - 如果找不到,检查各系统最常见的安装位置,区分「文件存在」和「文件不存在」。
- 只有在 PATH 里找不到时,才检查安装目录;这一步能直接指出「装了但没加 PATH」。
看输出判断
在一台没装 ffmpeg 的 Linux 上,输出是这样:
ffmpeg:未找到
ffprobe:未找到
常见安装位置:
不存在 /usr/bin/ffmpeg
不存在 /usr/local/bin/ffmpeg
不存在 /snap/bin/ffmpeg
怎么处理:
Linux:sudo apt install ffmpeg(Debian/Ubuntu)或 sudo dnf install ffmpeg(Fedora)
装完先关掉终端再重开,然后运行 ffmpeg -version 确认。
装好之后,大概是:
ffmpeg:7.1.1
ffprobe:7.1.1
路径:/opt/homebrew/bin/ffmpeg
状态:可用,视频脚本可以继续。
版本号和路径会随安装方式不同而变,不用逐字对上。

如果中间出现「存在 /usr/local/bin/ffmpeg」,但上面的 ffmpeg 仍是「未找到」,就是第二种情况:文件装了,但它所在的目录不在 PATH 里。按下一节把 bin 目录加进去。
按系统修 PATH
Windows
- 打开 ffmpeg.org,进入 Windows builds(gyan.dev 或 BtbN 的构建),下载
ffmpeg-release-essentials.zip。 - 解压到
C:\ffmpeg,确认这个文件存在:C:\ffmpeg\bin\ffmpeg.exe。 - 在开始菜单搜「环境变量」→「编辑系统环境变量」→「环境变量」。
- 在「用户变量」里选中
Path→「编辑」→「新建」→ 填C:\ffmpeg\bin→ 一路确定。加完回头看一眼,列表里出现C:\ffmpeg\bin就对了。 - 关掉所有终端窗口,重新打开,运行:
where ffmpeg
看到 C:\ffmpeg\bin\ffmpeg.exe 就成了。
注意加的是 bin 目录,不是 C:\ffmpeg。加错一层,终端还是找不到。
macOS
用 Homebrew:
brew install ffmpeg
which ffmpeg
Apple Silicon 的 Homebrew 在 /opt/homebrew,命令应该在 /opt/homebrew/bin/ffmpeg;Intel Mac 通常在 /usr/local/bin。如果 which 还是空,先确认 Homebrew 的 bin 在 PATH 里(~/.zshrc 是开终端时自动读的配置文件,source 让它当场生效):
brew --prefix
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
再重开终端,跑一次 which ffmpeg。
Linux
Debian / Ubuntu:
sudo apt install ffmpeg
Fedora:
sudo dnf install ffmpeg
装完用 which ffmpeg 确认,路径通常是 /usr/bin/ffmpeg。
已经装在别的位置
如果文件不在上面这些常见目录,找到 ffmpeg(Windows 是 ffmpeg.exe)实际所在的 bin 目录,把它加进 PATH 就行。规则只有一条:加到 bin,不是加到 exe 本身,也不是加到它的上一级目录。
改完 PATH 还是不行
按可能性从高到低查:
- 终端没重开。 Windows 的 cmd、PowerShell、VS Code 内置终端都要关掉重开;只关标签页不算。
- 改错了变量。 Windows 有「用户变量」和「系统变量」,改当前用户就用用户变量;路径拼错也会失效。
- bash 缓存了旧位置。 运行
hash -r;zsh 用rehash。 - 装到了另一个用户。 管理员账户装的,当前用户不一定能读到;改成当前用户安装,或换对应用户。
终端没重开
cmd、PowerShell、VS Code 内置终端都要关掉重开;只关标签页不算。
改错了变量
改当前用户就用「用户变量」;路径拼错同样失效。
bash 缓存了旧位置
运行 hash -r;zsh 用 rehash。
装到了另一个用户
管理员账户装的当前用户读不到,改成当前用户安装。
ffprobe 也要检查
站内处理视频的脚本不只用 ffmpeg,还用 ffprobe 读时长和尺寸。它通常和 ffmpeg 在同一个包里,装完整版就会一起出现。
单独确认:
ffprobe -version
如果 ffmpeg 有、ffprobe 没有,说明装的是裁剪包,重装完整版即可。
常见坑
1. 把 ffmpeg.exe 复制到项目目录
终端不会去当前目录找命令,除非写 ./ffmpeg.exe。站内脚本默认调用 ffmpeg,复制过去没用。
2. 只在当前终端 export
export PATH="/path/to/ffmpeg/bin:$PATH" 只对当前窗口有效,关掉就没了。写进 ~/.zshrc、~/.bashrc,或用 Windows 的环境变量界面。
3. 把 npm 的 ffmpeg-static 当成系统命令
它给的是一个文件路径,不是全局命令。脚本里可以 import 那个路径,但在终端直接敲 ffmpeg 仍然找不到。
4. 从不明来源下载
用 ffmpeg.org 上列的构建。装完先跑 ffmpeg -version,确认能输出。
下一步读什么
ffmpeg 能用之后,就可以做一条视频变三个平台版本了:改尺寸、抽封面帧、生成三版文案,都靠它。
如果 ffmpeg 装上了、npm install 又报错,先看npm install 报错。
这篇也是从 0 开始:第一台自动化工作台里的环境检查步骤;做完可以回到自媒体自动化入门按顺序往下走。
常见问题
我明明装了 ffmpeg,为什么终端还是找不到?
最常见的是 bin 目录没进 PATH,或者 PATH 改了但终端没重开。终端只在启动时读一次 PATH;已经开着的窗口、VS Code 内置终端都还是旧环境。先跑文中的检查脚本,它会告诉你文件在不在、在不在 PATH 里。
Windows 加完 PATH 要重启电脑吗?
不用。关掉所有终端窗口再重开就够了;如果用的是 VS Code 或 Cursor 的内置终端,整个编辑器都要退出重开,只关终端标签页不够。
brew 装了 ffmpeg,which 还是找不到?
Apple Silicon 的 Homebrew 装在 /opt/homebrew,bin 目录是 /opt/homebrew/bin。如果它不在 PATH 里,把 export PATH="/opt/homebrew/bin:$PATH" 写进 ~/.zshrc(开终端时自动读的配置文件),再 source 一次(让它当场生效)并重开终端。也可以用 brew --prefix 确认实际路径。
ffprobe 是什么,必须装吗?
ffprobe 和 ffmpeg 来自同一个项目,用来读视频的时长、尺寸、编码信息。站内处理视频尺寸和抽封面的脚本会用到它。官方安装包和 Homebrew 都会一起装;只装了 ffmpeg 的裁剪包可能缺它,重装完整版即可。
能不能把 ffmpeg.exe 放在脚本旁边直接用?
临时测试可以,用 ./ffmpeg.exe 或写绝对路径;但站内脚本默认调用 ffmpeg 这个命令,不会去脚本目录找。长期用还是把 bin 目录加进 PATH,换项目、换目录都不用改代码。
每周一张复习表
每周分享一张实用复习表,不收钱不打扰,想走随时走
邮箱存在 Cloudflare KV 里,只用来发每周更新;任何时候写信到hello@genwozuo.com说「退订」就删掉。详见隐私政策。