不能。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。