如何在PHP的shell_exec()中指定虚拟终端大小?
解决shell_exec()中设置虚拟终端大小的问题
你的原有代码无效,是因为shell_exec默认使用管道而非伪终端(PTY),stty命令无法在管道环境下修改终端尺寸——程序(比如yum)是通过读取终端的TIOCGWINSZ属性来获取窗口大小的,只有在PTY环境下这个属性才能被修改。
要实现这个需求,应该用proc_open来创建带PTY的子进程,具体实现如下:
function shell_exec_with_pty_size(string $cmd, int $columns = 999, int $rows = 999): string { $descriptorspec = [ 0 => ['pty'], // 标准输入绑定PTY 1 => ['pty'], // 标准输出绑定PTY 2 => ['pty'] // 标准错误绑定PTY ]; $process = proc_open($cmd, $descriptorspec, $pipes); if (!is_resource($process)) { throw new RuntimeException('无法创建子进程'); } // 获取PTY资源的文件描述符 $pty_fd = (int) $pipes[0]; // 构造TIOCSWINSZ结构体数据(Linux平台) $winsize = pack('S4', $rows, $columns, 0, 0); if (!defined('TIOCSWINSZ')) { define('TIOCSWINSZ', 0x5414); } fcntl($pty_fd, TIOCSWINSZ, $winsize); // 读取输出 $output = stream_get_contents($pipes[1]); $error = stream_get_contents($pipes[2]); // 关闭管道和进程 foreach ($pipes as $pipe) { fclose($pipe); } proc_close($process); // 合并标准输出和错误输出 return $output . $error; }
关键说明:
- 使用
proc_open创建带PTY的子进程,让目标程序认为自己运行在终端环境中。 - 通过
fcntl调用TIOCSWINSZ来设置PTY的窗口大小,这个系统调用会直接修改终端的尺寸属性,yum这类程序能正确读取到这个值。 - 相比
shell_exec,proc_open提供了对进程IO的更精细控制,确保PTY被正确绑定和配置。
针对yum的使用示例:
调用这个函数执行yum check-updates时,就能得到指定列数下的格式化输出:
$yum_output = shell_exec_with_pty_size('yum check-updates', 200, 999); // 此时$yum_output会是列宽200下的单行格式,方便解析
内容的提问来源于stack exchange,提问作者hanshenrik
相关产品推荐
相关产品推荐

