不能。Composer 的 run-script 命令仅执行 scripts 中定义的键名,不直接运行 .sh 或 .bat 文件;需显式调用 sh -c、cmd /c 或用 PHP 封装以确保跨平台兼容与安全执行。

run-script 能否直接执行 .sh 或 .bat 文件?
不能。Composer 的 run-script 命令只识别 scripts 部分定义的键名,它本身不解析或执行任意外部文件路径。你写 "scripts": {"build": "./build.sh"},Composer 会尝试把 ./build.sh 当作 PHP 脚本去加载(失败),而不是交给 shell 执行。
正确做法:用 shell 命令包装脚本路径
必须显式调用 sh、bash 或 cmd,让系统真正启动解释器。Windows 和 Linux 行为不同,需分开处理:
- Linux/macOS 下推荐用
sh -c包裹,避免 shebang 解析异常或权限问题 - Windows 下需用
cmd /c,且注意反斜杠转义和空格路径 - 跨平台项目建议统一用
php中转(见下一点),否则 CI/CD 容易因环境差异失败
"scripts": {
"build": "sh -c './build.sh'",
"test-win": "cmd /c build.bat",
"lint": "sh -c 'find src -name \"*.php\" | xargs php -l'"
}
为什么推荐用 PHP 封装 Shell 调用?
绕过平台差异和 Composer 对命令格式的限制,同时能做前置检查、错误捕获和路径标准化:
-
exec()/shell_exec()不会自动继承 Composer 的工作目录,需用getcwd()或__DIR__显式拼接 - 返回值需手动判断:
exec($cmd, $output, $returnCode)中$returnCode !== 0才算失败 - 敏感字符(如空格、括号)必须用
escapeshellarg()处理,否则脚本名含空格会中断执行
"scripts": {
"deploy": "php -r \"chdir(__DIR__); exec(escapeshellarg('./deploy.sh') . ' 2>&1', \$out, \$code); if (\$code !== 0) { echo implode(\"\\n\", \$out); exit(\$code); }\""
}
常见失败原因和验证步骤
执行 composer run-script xxx 报错时,先排除这几个硬性条件:
- 脚本文件没有可执行权限(Linux/macOS):
chmod +x ./build.sh - Windows 上用了 Unix 风格换行(LF),导致
cmd解析失败 —— 用dos2unix或编辑器转 CRLF -
composer.json中脚本定义末尾多了逗号(JSON 语法错误),导致整个scripts段被忽略 - 脚本里用了相对路径(如
../config/app.yml),但执行时工作目录不是预期位置 —— 建议全部改用$(dirname $0)/..或 PHP 的__DIR__
最稳妥的验证方式:先手动运行 sh -c './build.sh',确认它在终端里能成功,再放进 composer.json。










