【问题标题】:Use input pipe and manage keyboard使用输入管道和管理键盘
【发布时间】:2026-01-03 14:35:02
【问题描述】:

我尝试运行一个通过传入管道读取流的 PHP 脚本,我也想管理键盘:cat /etc/passwd|./readSlow.php 该脚本将从管道中读取每个字符并在标准输出上缓慢显示,直到用户按下“q”键(不按 RETURN)。 实际上,脚本读取管道并缓慢显示文本。但是当我按“q”时它并没有停止(它会显示它,我需要在“q”之后按 RETURN 键才能激活停止)。

#!/usr/bin/php
<?php
// ReadSlow

// This tool take a file in input and read it, character by caracter to the
// output.
// It add a sleep time between each character.

// Wait 0.2s between each char
$defaultSpeed = 0.5;

if (($input = fopen ("php://stdin", "r")) === false)
  die ("Can not open stdin\n");
if (($keyboard = fopen("/dev/tty", "r")) === false)
  die ("Can not open /dev/tty\n");
stream_set_blocking($keyboard, false);

$speed = $defaultSpeed;

while (($char = fgetc ($input)) !== false)
{
  if (($key = fgetc ($keyboard)) === "q") // get input from keyboard
    break;
  usleep ($speed * 1000000);
  echo "$char";
}
 
fclose ($input);

最后我希望有更多可用的密钥。

问题:我应该如何混合标准输入和键盘中的管道(不显示按下的键,不等待返回键)?

我尝试使用“stty”,但每次我都有“stty: 'standard input': Inappropriate ioctl for device”

我在 Linux 上,如果 Bash 有什么改变的话。

谢谢

【问题讨论】:

    标签: pipe keyboard php stdin


    【解决方案1】:

    你很亲密。默认情况下,Unix 上的终端/控制台又名“tty”设备以一次一行模式工作,让您有机会纠正小的打字错误。您需要将其关闭,stty 是这样做的好方法 - 但stty 在其标准输入上运行,并且您已重定向标准输入(使用管道),因此您需要将其重定向回 stty。在程序的开头尝试system("stty &lt;/dev/tty raw"),类似但在结尾使用-raw

    【讨论】:

    • 我添加了 -echo/echo 以不显示键入的密钥!惊人的 !非常感谢
    【解决方案2】:

    问题是stdin和tty是同一个输入通道。如果您可以不用管道就可以逃脱,请通过“./readSlow.php /etc/passwd”尝试以下代码。这会将要打印的文件作为命令行参数。命令“stty -echo”抑制按下的按键的输出。

        #!/usr/bin/php
        <?php
        // ReadSlow
        
        // This tool take a file in input and read it, character by caracter to the
        // output.
        // It add a sleep time between each character.
        
        // Wait 0.2s between each char
        $defaultSpeed = 0.5;
        
        if (($input = fopen ($argv[1], "r")) === false)
          die ("Can not open $argv[1]\n");
        if (($keyboard = fopen("/dev/tty", "r")) === false)
          die ("Can not open /dev/tty\n");
        stream_set_blocking($keyboard, false);
        
        system("stty -echo");
        
        $speed = $defaultSpeed;
        
        while (($char = fgetc ($input)) !== false)
        {
          if (($key = fgetc ($keyboard)) === "q") // get input from keyboard
            break;
          usleep ($speed * 1000000);
          echo "$char";
        }
        
        fclose ($input);
        echo "\n";
        system("stty echo");
    

    【讨论】:

    • 这是不正确的; 通常 stdin 与 tty 相同,但当 stdin 已被重定向(在这种情况下通过管道)/dev/tty 仍然是 tty。此外,stty -echo 不足以获取一次字符输入。
    • -echo/echo 删除显示的键但必须链接到 raw/-raw 才能在不按 RETURN 键的情况下捕获该键。非常感谢
    • 调用 stream_set_blocking($keyboard, false); 为 tty 捕获按下的键,而不必按 RETURN 键。