如何在 PHP 中正确使用 exec 函数执行带通配符()的 Shell 命令

2次阅读

如何在 PHP 中正确使用 exec 函数执行带通配符()的 Shell 命令

PHP 的 exec() 默认不保证在 bash 环境下运行,因此依赖 shell 特性(如 ` 通配符展开)的命令可能失败;需显式调用 bash 或改用 PHP 原生文件匹配函数(如 glob()`)替代。

php 的 `exec()` 默认不保证在 bash 环境下运行,因此依赖 shell 特性(如 `*` 通配符展开)的命令可能失败;需显式调用 bash 或改用 php 原生文件匹配函数(如 `glob()`)替代。

在 PHP 中调用 exec() 执行含通配符(如 *)的命令时,常见错误是:命令在终端中能正常运行(如 mediaconvert -t wav -i /home/20220228/11/*01.rec -o test.mp3),但在 PHP 脚本中却无法匹配文件,返回空结果或报错。根本原因在于: 通配符展开(globbing)是 shell 的特性,而非操作系统内核功能 ——而 PHP 的 exec() 默认调用的是系统默认 shell(通常是 /bin/sh),它对通配符的支持有限(POSIX sh 仅支持基础 glob,且行为受环境严格约束),尤其在 Web 服务器(如 Apache)上下文中,执行用户(如 apache 或 www-data)往往被配置为使用 /sbin/nologin 作为登录 shell,实际回退至极简 /bin/sh,不支持 bash 特有的扩展语法(如 **, {a,b}, 数组展开等)。

✅ 验证当前执行环境

首先确认 PHP 进程实际使用的 shell:

<?php exec('echo $0', $shell); exec('echo "$SHELL"', $full_shell); var_dump('Current shell:', $shell[0], 'SHELL env:', $full_shell[0]); ?>
  • CLI 模式下常输出 /bin/bash;
  • Web 模式(Apache/Nginx + PHP-FPM)下多为 /sbin/nologin 或 /bin/sh —— 此时 * 可能不展开。

? 小技巧:直接测试通配符是否生效

exec('ls -1 /home/20220228/11/*01.rec 2>/dev/null', $files); var_dump($files); // 若为空,说明 glob 未触发 

✅ 解决方案一:强制使用 bash 执行(推荐用于简单场景)

通过显式调用 bash -c 包裹命令,确保通配符由 bash 解析:

立即学习 PHP 免费学习笔记(深入)”;

$cmd = 'bash -c "mediaconvert -t wav -i /home/20220228/11/*01.rec -o /var/www/html/test.mp3"'; exec($cmd, $output, $return_code);  if ($return_code !== 0) {error_log("Command failed with code {$return_code}: " . implode("n", $output)); }

⚠️ 注意事项:

  • 确保目标服务器已安装 bash(which bash 可验证);
  • 命令字符串需用双引号包裹,内部变量 / 通配符才可被 bash 解析;
  • 避免拼接用户输入,防止 shell 注入(应使用 escapeshellarg() 处理动态路径)。

✅ 解决方案二:用 PHP 原生 glob() 替代 shell 展开(更安全、跨平台)

当只需匹配单个或少量文件时,优先使用 PHP 内置函数,完全规避 shell 依赖:

$pattern = '/home/20220228/11/*01.rec'; $files = glob($pattern);  if (empty($files)) {throw new RuntimeException("No files matched pattern: {$pattern}"); }  // 假设只处理第一个匹配项(符合原意“目录中仅一个文件”)$input_file = $files[0]; $output_file = '/var/www/html/test.mp3';  $cmd = sprintf('mediaconvert -t wav -i %s -o %s',      escapeshellarg($input_file),      escapeshellarg($output_file) ); exec($cmd, $output, $return_code);  if ($return_code !== 0) {throw new RuntimeException("mediaconvert failed: " . implode("n", $output)); }

✅ 优势:

  • 不依赖 shell 类型,全环境一致;
  • 自动处理路径中的空格、特殊字符(escapeshellarg 保障安全);
  • 易于调试(可 var_dump($files) 直接查看匹配结果);
  • 符合 PSR-12 编码规范,可读性与可维护性更高。

? 总结建议

场景 推荐方案 理由
快速验证、脚本简单、确定有 bash bash -c “…” 开发效率高,语义贴近原始命令
生产环境、Web 服务、需高安全性 glob() + escapeshellarg() 消除 shell 差异风险,防御注入,逻辑可控
复杂通配(如递归 **、花括号展开 {a,b}) 必须用 bash -c glob() 不支持此类扩展语法

最后提醒:无论采用哪种方式,务必检查 $return_code 并捕获 $output,避免静默失败;同时确保 Web 服务器用户对输入 / 输出路径具有读写权限(如 chown apache:apache /var/www/html/)。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-23发表,共计2206字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources