如何在 Perl 中获取用户输入而不等待输入?

发布于 2024-08-29 17:17:51 字数 199 浏览 8 评论 0原文

我正在尝试用 Perl 制作一个交互式 shell 脚本。

我能找到的唯一用户输入如下:

 $name = <STDIN>;
 print STDOUT "Hello $name\n";

但在这种情况下,用户必须始终按 Enter 键才能使更改生效。 如何让程序在按下按钮后立即继续运行?

I am trying to make an interactive shell script in Perl.

The only user input I can find is the following:

 $name = <STDIN>;
 print STDOUT "Hello $name\n";

But in this the user must always press enter for the changes to take effect.
How can I get the program to proceed immediately after a button has been pressed?

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

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

发布评论

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

评论(2

如果没结果 2024-09-05 17:17:51

来自 perlfaq8 的回答 如何只读取一个键而不等待返回键?


控制输入缓冲是一个非常依赖于系统的问题。在许多系统上,您可以只使用 stty 命令,如 perlfunc 中的 getc 所示,但如您所见,这已经让您遇到了可移植性障碍。

open(TTY, "+</dev/tty") or die "no tty: $!";
system "stty  cbreak </dev/tty >/dev/tty 2>&1";
$key = getc(TTY);       # perhaps this works
# OR ELSE
sysread(TTY, $key, 1);  # probably this does
system "stty -cbreak </dev/tty >/dev/tty 2>&1";

CPAN 的 Term::ReadKey 模块提供了一个易于使用的界面,该界面应该比为每个密钥向 stty 敲击更有效。它甚至包括对 Windows 的有限支持。

use Term::ReadKey;
ReadMode('cbreak');
$key = ReadKey(0);
ReadMode('normal');

但是,使用该代码需要您有一个可用的 C 编译器,并且可以使用它来构建和安装 CPAN 模块。这是使用标准 POSIX 模块的解决方案,该模块已在您的系统上(假设您的系统支持 POSIX)。

use HotKey;
$key = readkey();

这里是 HotKey 模块,它隐藏了一些令人费解的调用来操作 POSIX termios 结构。

# HotKey.pm
package HotKey;

@ISA = qw(Exporter);
@EXPORT = qw(cbreak cooked readkey);

use strict;
use POSIX qw(:termios_h);
my ($term, $oterm, $echo, $noecho, $fd_stdin);

$fd_stdin = fileno(STDIN);
$term     = POSIX::Termios->new();
$term->getattr($fd_stdin);
$oterm     = $term->getlflag();

$echo     = ECHO | ECHOK | ICANON;
$noecho   = $oterm & ~$echo;

sub cbreak {
    $term->setlflag($noecho);  # ok, so i don't want echo either
    $term->setcc(VTIME, 1);
    $term->setattr($fd_stdin, TCSANOW);
}

sub cooked {
    $term->setlflag($oterm);
    $term->setcc(VTIME, 0);
    $term->setattr($fd_stdin, TCSANOW);
}

sub readkey {
    my $key = '';
    cbreak();
    sysread(STDIN, $key, 1);
    cooked();
    return $key;
}

END { cooked() }

1;

From perlfaq8's answer to How do I read just one key without waiting for a return key?
:


Controlling input buffering is a remarkably system-dependent matter. On many systems, you can just use the stty command as shown in getc in perlfunc, but as you see, that's already getting you into portability snags.

open(TTY, "+</dev/tty") or die "no tty: $!";
system "stty  cbreak </dev/tty >/dev/tty 2>&1";
$key = getc(TTY);       # perhaps this works
# OR ELSE
sysread(TTY, $key, 1);  # probably this does
system "stty -cbreak </dev/tty >/dev/tty 2>&1";

The Term::ReadKey module from CPAN offers an easy-to-use interface that should be more efficient than shelling out to stty for each key. It even includes limited support for Windows.

use Term::ReadKey;
ReadMode('cbreak');
$key = ReadKey(0);
ReadMode('normal');

However, using the code requires that you have a working C compiler and can use it to build and install a CPAN module. Here's a solution using the standard POSIX module, which is already on your system (assuming your system supports POSIX).

use HotKey;
$key = readkey();

And here's the HotKey module, which hides the somewhat mystifying calls to manipulate the POSIX termios structures.

# HotKey.pm
package HotKey;

@ISA = qw(Exporter);
@EXPORT = qw(cbreak cooked readkey);

use strict;
use POSIX qw(:termios_h);
my ($term, $oterm, $echo, $noecho, $fd_stdin);

$fd_stdin = fileno(STDIN);
$term     = POSIX::Termios->new();
$term->getattr($fd_stdin);
$oterm     = $term->getlflag();

$echo     = ECHO | ECHOK | ICANON;
$noecho   = $oterm & ~$echo;

sub cbreak {
    $term->setlflag($noecho);  # ok, so i don't want echo either
    $term->setcc(VTIME, 1);
    $term->setattr($fd_stdin, TCSANOW);
}

sub cooked {
    $term->setlflag($oterm);
    $term->setcc(VTIME, 0);
    $term->setattr($fd_stdin, TCSANOW);
}

sub readkey {
    my $key = '';
    cbreak();
    sysread(STDIN, $key, 1);
    cooked();
    return $key;
}

END { cooked() }

1;
征棹 2024-09-05 17:17:51

您可以使用 Term::ReadKey 模块来检查按键。

You can use the Term::ReadKey module to check for a keypress.

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