如何使用Composer run-script调用外部Shell脚本或批处理文件?

11次阅读

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

如何使用Composer run-script调用外部Shell脚本或批处理文件?

run-script 能否直接执行 .sh 或 .bat 文件?

不能。Composer 的 run-script 命令只识别 scripts 部分定义的键名,它本身不解析或执行任意外部文件路径。你写 "scripts": {"build": "./build.sh"},Composer 会尝试把 ./build.sh 当作 PHP 脚本去加载(失败),而不是交给 shell 执行。

正确做法:用 shell 命令包装脚本路径

必须显式调用 shbashcmd,让系统真正启动解释器。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

text=ZqhQzanResources