Laravel9 调用bash命令复制清空日志失效的正确实现方法
问题根因
当前代码里Symfony Process的用法完全错误,具体问题点:
- Process构造函数默认接收的是拆分后的命令参数数组,把整行bash命令作为单个数组元素传入时,系统会把整段字符串当成可执行文件名查找,必然执行失败
>是Bash等Shell的内置重定向语法,不是独立可执行程序,直接作为命令传入完全无法被识别- 代码里用的是相对路径,Artisan命令执行时的工作目录不固定,大概率找不到对应日志文件
- 归档日志文件名写死为
laravel_new.log,多次执行会直接覆盖历史归档,不符合日志留存的常规需求
实现方案
方案1:修正Process调用逻辑
如果必须通过系统命令实现,需要区分普通命令和Shell内置语法的调用方式,同时使用绝对路径:
public function handle() { $originalLog = storage_path('logs/laravel.log'); $archiveLog = storage_path('logs/laravel-'.Carbon::now()->format('YmdHis').'.log'); // 普通命令以参数数组形式传入,设置工作目录为项目根路径 $copyProcess = new Process(['cp', $originalLog, $archiveLog]); $copyProcess->setWorkingDirectory(base_path()); // 用mustRun替代run,命令执行失败时会直接抛出异常,方便排查错误 $copyProcess->mustRun(); // 含重定向、管道符的Shell语法,用fromShellCommandline创建实例 $eraseProcess = Process::fromShellCommandline('> "$LOG_PATH"', base_path()); // 通过环境变量传参,避免转义问题 $eraseProcess->run(null, ['LOG_PATH' => $originalLog]); $this->info('日志归档完成,原日志已清空'); return Command::SUCCESS; }
方案2:用PHP原生文件操作实现(推荐)
不需要依赖外部系统命令,跨平台兼容性更好,也不会出现Shell命令的各类转义、权限问题:
public function handle() { $originalLog = storage_path('logs/laravel.log'); if (!file_exists($originalLog)) { $this->warn('日志文件不存在,无需执行操作'); return Command::SUCCESS; } $archiveLog = storage_path('logs/laravel-'.Carbon::now()->format('YmdHis').'.log'); // 复制原日志到归档路径 copy($originalLog, $archiveLog); // 清空原日志内容 file_put_contents($originalLog, ''); $this->info('日志归档完成,原日志已清空'); return Command::SUCCESS; }
这个方案在Windows、Linux、macOS环境下都能正常运行,不需要额外配置,稳定性远高于调用外部Shell命令。
内容的提问来源于stack exchange,提问作者El Hombre Sin Nombre
相关产品推荐
相关产品推荐

