Jenkins sh 提示 command not found 速查:agent PATH、容器镜像与工具自动安装
更新时间:2026-10-24。FAQ 速查页,面向构建日志里躺着
sh: mvn: not found、退出码 127,但登上 agent 手工跑同样的命令却好使的同学。这类报错的核心矛盾是:你登录 agent 用的是登录 shell,Jenkins 起 sh 步骤用的是非登录非交互 shell,两者的 PATH 来自完全不同的配置文件。你在.bashrc里 export 的路径,Jenkins 根本读不到。病因收敛在六根轴上:agent 非登录 shell 不加载 bashrc/profile、PATH 改在用户级配置而 Jenkins 以系统服务身份跑、容器 agent 镜像自带 PATH 精简缺工具、Jenkinstools指令自动安装的工具目录没注入 PATH、多 agent 环境不一致「这台能跑那台不能」、以及 Windows agent 上路径分隔符与命令后缀的差异。顺一遍基本必中。如果是命令存在但执行返回别的非零码,转 Jenkins 退出码非零速查。
本文要回答的问题
- 同一台机器,手工跑好使,Jenkins 里就 not found,为什么?
- 在 agent 的
.bashrc里加了 PATH,为什么流水线里没生效? - 容器 agent 里缺工具,装在哪、怎么让它进 PATH?
tools { maven 'M3' }配了,为什么 mvn 还是 not found?- 同样的流水线,换了一台 agent 就 127,怎么对齐环境?
一、报错原文与典型现象
命令找不到的报错形态固定(控制器地址以 jenkins.example.com 占位,路径以 /proj/demo 占位):
# sh 步骤里命令不存在
[Pipeline] sh
+ mvn -v
/proj/demo@tmp/durable-xxxx/script.sh: line 1: mvn: not found
ERROR: script returned exit code 127# dash 风格报错的措辞
sh: 1: mvn: not found
# 或 bash 风格
bash: mvn: command not found# tools 自动安装未生效的样子
[Pipeline] tool
[Pipeline] sh
+ mvn -v
sh: mvn: not found
# 工具装到了别处,PATH 里没有读现象抓两条线索:退出码恒为 127(126 是找到但没执行权限,别混);报错行里的 shell 名字透露执行环境——sh: 1: xxx: not found 这种带序号的格式来自 dash(Debian/Ubuntu 系默认 sh),bash: xxx: command not found 来自 bash。两者都找不到时,先别急着装软件,先看 PATH 里到底有没有工具所在的目录。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| 手工好使、Jenkins 里 127 | 登录 shell 与非登录 shell PATH 不同 | sh 里跑 echo 对比两边 PATH | PATH 写进节点环境变量或流水线 environment |
| 改了 bashrc 不生效 | 非登录非交互 shell 不读 bashrc | sh 里跑 sh -c 'env' 看实际环境 | 改用 Jenkins 节点配置注入 PATH |
| 容器 agent 缺工具 | 镜像精简,工具根本没装 | 同镜像起容器 which 验证 | 换含工具的镜像或 Dockerfile 里装好 |
| tools 配了仍 not found | 自动安装目录未注入 PATH | 看 tool 步骤输出的安装路径 | tools 指令放对层级,或显式 env.PATH 拼接 |
| 这台 agent 能跑那台不能 | 多 agent 环境不一致 | 两台 agent 分别跑 which 对比 | 用 label 钉死节点,或容器化统一环境 |
| Windows 上命令明明存在 | 分隔符或 .exe/.bat 后缀差异 | sh 里跑 type 命令看解析结果 | 用完整路径或统一走 pwsh 步骤 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓分水岭:先在出事的 sh 步骤里跑一条取证命令(echo 打印 PATH 再 which 目标命令),结果只有两种——PATH 里压根没有工具所在目录(走左支,修 PATH 注入);目录在 PATH 里但工具文件不存在(走右支,真没装,修镜像或自动安装)。取证一条命令定性,不要凭猜。
四、逐条排查展开
核心矛盾:登录 shell 与非登录 shell 的 PATH 是两套。 你 SSH 登上 agent,系统依次加载 /etc/profile、~/.bash_profile(或 ~/.profile),交互式 bash 再加载 ~/.bashrc——你 export 的 PATH 在这一串里生效。Jenkins 的 sh 步骤走的是非登录非交互 shell(多数发行版是 /bin/sh,Ubuntu 上是 dash):不读 profile、不读 bashrc,PATH 只来自进程启动时继承的环境——也就是 Jenkins agent 进程自己的环境。取证姿势:在流水线里跑 sh 'echo "PATH is: " + env.PATH ?: ""' 不直观,直接 sh 'echo $PATH' 与 sh 'which mvn || true',再和你登录后手工跑的结果对比,差异一目了然。
修法三选一,按团队习惯定死一种。 第一条路:节点级注入——系统管理 → 节点配置 → 环境变量,给该 agent 加 PATH+EXTRA 形式的键值(Jenkins 支持 PATH+NAME 语法把值追加到既有 PATH),所有任务生效,改一次管全节点。第二条路:任务级注入——流水线顶层 environment { PATH = "/opt/maven/bin:${PATH}" },只影响本任务,适合个别任务的特殊工具。第三条路:把工具装到标准目录(/usr/local/bin 等本来就在默认 PATH 里的位置),不碰任何配置。团队纪律:禁止把 PATH 修复写进每个 sh 步骤的前缀里,那是把配置散进一百个 Jenkinsfile。
容器 agent:PATH 问题的重灾区,但性质不同。 Kubernetes 插件或 Docker agent 起容器跑构建时,PATH 来自镜像本身的 ENV 指令——镜像里没装 mvn,你改宿主机的节点配置毫无作用。取证:用同一个镜像本地起容器跑 which mvn,没有就是没有。修法两条:一是换用含工具链的镜像(官方 maven、gradle、node 镜像或团队自建 all-in-one 构建镜像);二是在自建镜像的 Dockerfile 里把工具装好并用 ENV PATH=... 固化。容器化路线顺带解决了多 agent 不一致问题——镜像是唯一事实源,跑在哪台宿主机都一样。
tools 自动安装:装是装了,PATH 没指过去。 tools { maven 'M3' } 的语义是:声明式流水线在进入 stage 前把名为 M3 的全局工具(系统管理 → Global Tool Configuration 里定义)自动安装好,并把它的 bin 目录前置进 PATH。失效的三种典型:一,工具名 'M3' 和全局配置里的名字对不上(大小写、空格敏感),tool 步骤静默失败或装了个寂寞;二,tools 指令写在了错误的层级——声明式里它只对所在 stage 生效,stage A 配的 tools 在 stage B 的 sh 里不存在;三,脚本式流水线用 tool 'M3' 只返回安装路径字符串,你必须自己 env.PATH = "${tool 'M3'}/bin:${env.PATH}" 拼接,少了这一步照样 127。排查时先看构建日志里 [Pipeline] tool 段落输出的真实安装路径。
多 agent 漂移:能跑的那台不代表环境是对的。 「昨天还好好的」往往对应「今天调度到了另一台 agent」。裸机 agent 池的常态:运维在某台机器上手工装过工具,其余节点没有。短期止血:给任务加 agent { label 'has-maven' } 钉到装好的节点上。长期解法只有一条——agent 环境声明化:要么容器镜像统一,要么用 Ansible 之类的配置管理把工具清单铺到所有节点,禁止手工装机。环境漂移相关的调度问题可对照 Jenkins 节点离线速查 一起看。
Windows agent 的两个特异点。 一,PATH 分隔符是分号不是冒号,Jenkinsfile 里拼 PATH 用 ; 拼接;二,命令解析有后缀概念——mvn 在 Windows 上实际是 mvn.cmd,sh 步骤(如果装了 Git Bash 类环境)与 bat 步骤的解析路径不一样。跨平台团队建议:Windows agent 上统一用 pwsh 步骤,命令名写全,路径用环境变量引用,不写死盘符。
五、规范做法与预防
- PATH 注入定死一处:节点级(节点配置环境变量)或任务级(顶层 environment)二选一,禁止 sh 步骤前缀里随处拼接。
- 优先容器化 agent:构建镜像即环境事实源,Dockerfile 里
ENV PATH固化,多 agent 漂移问题连根拔掉。 - tools 指令放对层级:声明式里 tools 只对所在 stage 生效,跨 stage 要用的工具放顶层 tools;脚本式记得手动拼 env.PATH。
- 工具清单声明化:每个任务需要的工具与版本写进 Jenkinsfile 头部注释或共享库,新 agent 按清单铺,不靠记忆。
- 取证命令进手册:
echo $PATH加which xxx是 127 的第一反应,写进团队排错手册,先取证后动手。 - Windows 统一 pwsh:bat 与 sh 混用是后缀解析噩梦的来源,Windows 节点统一 pwsh 步骤。
这一篇在知识体系里的位置
本篇是 Jenkins 排错速查簇的「环境解析」入口篇:命令找到了但执行返回非零看 Jenkins 退出码非零速查;PATH 对了但环境变量值不展开看 Jenkins 环境变量不展开速查;命令存在但依赖的文件路径找不到看 Jenkins 路径不存在速查;agent 根本连不上看 Jenkins 节点离线速查。「先 echo PATH 取证 → PATH 缺目录修注入、目录有但无文件修安装」这条主线对一切 127 通用。
一句话总结
Jenkins 报 command not found(退出码恒为 127)先在出事的 sh 步骤里跑 echo $PATH 与 which xxx 取证:PATH 里没有工具目录是注入问题——你登录 shell 改的 bashrc 对 Jenkins 的非登录非交互 shell 无效,PATH 要走节点配置环境变量或流水线顶层 environment 注入;目录在 PATH 里但文件不存在是真没装——容器 agent 换含工具的镜像或 Dockerfile 里 ENV 固化,tools 自动安装注意工具名逐字符对上、指令放对层级、脚本式记得手动拼 env.PATH。多 agent 漂移靠容器化或配置管理根治,Windows 节点统一 pwsh。取证先行、注入定死一处、环境声明化,这类报错基本绝迹。