PHP中重新打开管道向可执行程序写入多条独立命令问题咨询
故障根因
- 调用
fclose($pipes[0])关闭bash进程的标准输入管道后,bash会检测到输入EOF直接终止运行,后续对管道的所有操作都没有生效的基础 popen()是用于启动新进程并创建新管道的接口,完全不支持重新打开已关闭的现有管道,属于API调用逻辑错误- 未做特殊配置的前提下,
stream_get_contents($pipes[1])会一直阻塞等待输出端返回EOF,只有bash进程退出时才会结束等待,因此无法在进程运行期间分批读取多条命令的输出
可用实现方案
核心逻辑是不要提前关闭输入管道,每输入一条命令加换行触发执行,刷入缓冲区后读取对应输出,所有命令执行完成后再终止bash进程,参考实现代码如下:
<?php ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); $descriptorspec = [ 0 => ["pipe", "r"], 1 => ["pipe", "w"], 2 => ["file", "/tmp/error-output.txt", "a"] ]; $cwd = '/tmp'; $env = []; $process = proc_open('/bin/bash', $descriptorspec, $pipes, $cwd, $env); $cmds = ["whoami", "pwd"]; if (is_resource($process)) { // 将输出管道设置为非阻塞模式,避免读取操作卡死 stream_set_blocking($pipes[1], false); foreach ($cmds as $cmd) { // 命令后拼接换行符,模拟终端输入回车触发执行 fwrite($pipes[0], $cmd . PHP_EOL); // 强制刷新缓冲区,确保命令立刻发送给bash进程 fflush($pipes[0]); // 短暂等待命令执行完成,可根据实际命令运行时长调整 usleep(100000); // 读取当前命令输出 $output = stream_get_contents($pipes[1]); echo "命令 {$cmd} 执行结果:\n" . $output . "\n------------------------\n"; } // 所有命令执行完成后再关闭管道、结束进程 fclose($pipes[0]); fclose($pipes[1]); proc_close($process); }
如果需要更精准的输出边界判断,避免固定等待时间的误差,可以在每条命令末尾追加自定义分隔符输出,读取输出时直到匹配到分隔符再停止,不需要固定时长等待。
内容的提问来源于stack exchange,提问作者no one
相关产品推荐
相关产品推荐

