执行“更少”从带有滚动功能的命令行 PHP

发布于 2024-09-14 10:07:43 字数 181 浏览 9 评论 0原文

我想从 PHP 命令行执行 less 和类似的程序。

我已经尝试了常见的方法(exec、shell_exec、passthru 等),虽然其中许多可以将文件转储到屏幕上,但在我可以使用它之前该进程就终止了。如果我想要cat,我会使用它。

我如何以这种方式执行程序?

I want to execute less and similar programs from the command-line in PHP.

I have tried the usual suspects (exec, shell_exec, passthru, etc), and while many of them can dump the file to the screen, the process is terminated before I can make use of it. If I wanted cat, I'd use it.

How do I execute a program in this fashion?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

醉酒的小男人 2024-09-21 10:07:43

您可以使用 proc_open 通过管道向进程提供输入并从进程获取输出。然而,它似乎并不允许用户通过管道进行交互,因为它基本上降级为 cat 命令。这是我的第一个(失败的)方法:

<?php
$dspec = array(
  0 = array('pipe', 'r'), // pipe to child process's stdin
  1 = array('pipe', 'w'), // pipe from child process's stdout
  2 = array('file', 'error_log', 'a'), // stderr dumped to file
);
// run the external command
$proc = proc_open('less name_of_file_here', $dspec, $pipes, null, null);
if (is_resource($proc)) {
  while (($cmd = readline('')) != 'q') {
    // if the external command expects input, it will get it from us here
    fwrite($pipes[0], $cmd);
    fflush($pipes[0]);
    // we can get the response from the external command here
    echo fread($pipes[1], 1024);
  }
fclose($pipes[0]);
fclose($pipes[1]);
echo proc_close($proc);

我想对于某些命令来说,这种方法可能实际上有效 - 并且在 proc_open 的 php 手册页中有一些示例可能有助于查看 - 但对于 less,你会得到整个文件,并且无法进行交互,可能是由于 Viper_Sb 的答案提到的原因。

...但如果这就是您所需要的,那么模拟 less 似乎很容易。例如,您可以将命令的输出读取到行数组中,并以小块的形式提供:

<?php
$pid = popen('cat name_of_file_here', 'r');
$buf = array();
while ($s = fgets($pid, 1024))
  $buf[] = $s;
pclose($pid);
for ($i = 0; $i < count($buf)/25 && readline('more') != 'q'; $i++) {
  for ($j = 0; $j < 25; $j++) {
    echo array_shift($buf);
  }
}

You could use proc_open to feed input to and get output back from a process via pipes. However, it doesn't seem like less allows for user interaction via pipes as it basically degrades to a cat command. Here's my first (failed) approach:

<?php
$dspec = array(
  0 = array('pipe', 'r'), // pipe to child process's stdin
  1 = array('pipe', 'w'), // pipe from child process's stdout
  2 = array('file', 'error_log', 'a'), // stderr dumped to file
);
// run the external command
$proc = proc_open('less name_of_file_here', $dspec, $pipes, null, null);
if (is_resource($proc)) {
  while (($cmd = readline('')) != 'q') {
    // if the external command expects input, it will get it from us here
    fwrite($pipes[0], $cmd);
    fflush($pipes[0]);
    // we can get the response from the external command here
    echo fread($pipes[1], 1024);
  }
fclose($pipes[0]);
fclose($pipes[1]);
echo proc_close($proc);

I guess for some commands this approach might actually work - and there are some examples in the php manpage for proc_open that might be helpful to look over - but for less, you get the whole file back and no possibility for interaction, maybe for reasons mentioned by Viper_Sb's answer.

...But it seems easy enough to simulate less if that's all you need. For example, you could read the output of the command into an array of lines and feed it in bite-sized chunks:

<?php
$pid = popen('cat name_of_file_here', 'r');
$buf = array();
while ($s = fgets($pid, 1024))
  $buf[] = $s;
pclose($pid);
for ($i = 0; $i < count($buf)/25 && readline('more') != 'q'; $i++) {
  for ($j = 0; $j < 25; $j++) {
    echo array_shift($buf);
  }
}
只为一人 2024-09-21 10:07:43

我不相信这是可能的。 PHP 不是 VM/shell 环境,它访问其他程序的命令都将控制权返回给它,并且在 PHP 运行时通常没有交互。

最后一件事,尝试使用反引号运算符,如果这不起作用,那么我很确定如果不自己编写一些可以休眠并允许用户输入等的内容,您就无法做到这一点...默认情况下没有

`nano file.txt`

I don't believe this is possible. PHP is not a VM/shell environment, the commands it has to access other programs all return control to it, and normally there is no interaction while PHP is running.

One last thing, try with the backtick operators, if that doesn't work then I'm pretty sure you can't do this without writing up something yourself that will sleep and allow user input etc... by default no

`nano file.txt`
呆萌少年 2024-09-21 10:07:43

添加 exec('stty cbreak'); PHP 脚本也解决了这个问题。

我将以下内容放入由 php.ini 中的 auto_prepend_file 设置定义的文件中

,因此,我将 php.ini 编辑为以下内容:

auto_prepend_file = /path/to/prepend.php

然后在 /path/to/prepend.php 中,我将添加以下行:

if (php_sapi_name() == 'cli') exec('stty cbreak');

我不太确定原因。我读过 PHP 的错误报告。但我不确定版本。我注意到以下设置存在问题:

$ php -v
PHP 5.3.3 (cli) (built: Jul 12 2013 20:35:47)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

但是,以下设置并未显示该问题:

# php -v
PHP 5.3.26 (cli) (built: Oct 21 2013 16:50:03)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
    with the ionCube PHP Loader v4.4.1, Copyright (c) 2002-2013, by ionCube Ltd.

值得注意的是,没有问题的版本使用的是 cPanel,另一个版本使用的是通过 yum 安装的默认 CentOS 6。

Adding exec('stty cbreak'); to the PHP script also fixes the issue.

I put the following in a file defined by the auto_prepend_file setting in php.ini

So, I would do something like edit php.ini to the following:

auto_prepend_file = /path/to/prepend.php

Then in, /path/to/prepend.php, I would add the following line:

if (php_sapi_name() == 'cli') exec('stty cbreak');

I'm not exactly sure of the cause. I've read bug reports for PHP. I'm not sure about versions though. I noticed the problem with the following setup:

$ php -v
PHP 5.3.3 (cli) (built: Jul 12 2013 20:35:47)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

However, the following did not show the issue:

# php -v
PHP 5.3.26 (cli) (built: Oct 21 2013 16:50:03)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
    with the ionCube PHP Loader v4.4.1, Copyright (c) 2002-2013, by ionCube Ltd.

It is worth noting that the version without the issue was using cPanel and the other was using the default CentOS 6 install via yum.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文