exec返回状态码总为0但命令实际失败,通常因shell命令自身退出码设计不符语义(如curl默认不因HTTP非2xx报错),需用-curl -f或sh -c 'cmd || exit 1'等显式控制;$return_var为null主因是未传引用或exec被disable_functions禁用。

exec 返回状态码总是 0,但命令明明失败了
这通常不是 PHP 的问题,而是 shell 命令本身退出码没按预期返回。比如 curl 默认不因 HTTP 状态码非 2xx 而报错(退出码仍是 0),grep 在没匹配时返回 1(被误判为失败),而 ls /nonexist 才真返回 2。关键要分清:shell 层退出码 ≠ 应用层语义成功。
实操建议:
- 用
set -e或显式检查:把命令包进 shell 脚本里,比如sh -c 'curl -s http://api/health || exit 1' - 对
curl加-f参数强制非 2xx 时返回非 0:curl -sf http://api/health - 对
grep用-q+||控制逻辑,别直接依赖其退出码做判断 - 永远用
$return_var接收,而不是靠exec()返回值——后者只是最后一行文本,和状态无关
为什么 $return_var 是 null 或没变化
根本原因是第三个参数没传引用,或者函数调用时漏写了它。PHP 的 exec() 不会自动填充 $return_var,必须显式传入变量引用。
常见错误写法:exec('ls', $output, $return_var) —— 这里 $return_var 是值传递,不会被修改。
立即学习“PHP免费学习笔记(深入)”;
正确写法必须带 &:
exec('ls /tmp', $output, $return_var);
// 或更安全地初始化再传:
$return_var = -1;
exec('ls /tmp', $output, $return_var);
如果仍为 null,说明命令根本没执行(比如被 disable_functions 拦截),此时 $output 也是空数组,需优先排查环境配置。
status code 127 和 126 分别代表什么
这两个是 shell 层的通用错误码,和具体命令无关:
-
127:命令未找到(command not found)→ 检查路径,比如用/usr/bin/curl替代裸curl -
126:找到了文件但不可执行(权限不足或不是可执行格式)→ls -l /path/to/binary看权限,必要时加chmod +x
注意:PHP 不会把 stderr 内容自动映射到 $return_var,所以看到 127 时,$output 里通常为空,得靠 2>&1 把错误流合并进来才能看到真实提示:
exec('missing-cmd 2>&1', $output, $return_var); // $output[0] 会是 "bash: missing-cmd: command not found"
线上环境 exec 状态码始终为 0,本地却正常
大概率是线上禁用了 exec,但 PHP 没报错、也不改 $return_var,导致它保持初始值(比如 null 或上一次的旧值)。这不是 bug,是设计如此——函数不执行,参数自然不更新。
验证方式最直接:
- 在代码里插一句:
exec('echo OK 2>&1', $test, $code); var_dump($test, $code); - 如果
$test === []且$code === null,基本可断定exec被禁用 - 立刻查
ini_get('disable_functions'),确认是否含exec;注意 CLI 和 Web(如 fpm)的 php.ini 可能不同
真正容易被忽略的是:即使 $return_var 是 0,也不能反推命令成功——它只表示 shell 进程退出码为 0,而 shell 进程可能什么都没干就退出了。



















