在进程 运行 时从键盘读取一个键

reading a key from keyboard while the process is running

我用 wget 在 Linux-Gnu 中用 Perl[=44 写了一个简单的脚本来管理下载时间(开始和完成) =].没有问题,一切正常,除了我希望 我可以在进程 运行ning.
时从键盘读取一个键 我在屏幕上显示了一个我不想停止的简单运动动画,然后读取键。

例如 mplayermpv 当你在命令行 运行 它时,你可以按 q 退出或 s 从屏幕拍照。

脚本的一部分:

do {
    system( "clear" );
    ($h, $m, $s) = k5mt::second_to_clock(  $till_shutdown );

    set_screen();
    set_screen( 24 );

    set_screen();
    say "download was started ...";

    set_screen();
    set_screen( 24 );

    set_screen();
    printf "till finish:    %02d %02d %02d\n", $h, $m, $s;

    set_screen();
    set_screen( 24 );

    set_screen();
    say "wget pid: [$wget_pid]";

    set_screen();
    set_screen( 24 );

    set_screen();
    $waiting_temp .= $animation[ $counter_animation++ ];
    say $waiting_temp;
    if( length( $waiting ) == $counter_animation ){
        $waiting_temp = "";
        $counter_animation = 0;
    }

    set_screen();
    set_screen( 24 );

    sleep 1;
    $till_shutdown--;

} while( $till_shutdown );  

单词waiting till finish.....连续显示(没有中断),我想读一个像q这样的键退出程序.

更新

我正在寻找一个包含尽可能多选项的解决方案,如果我只想退出程序,我只需告诉用户按 Ctrl + C

是否可以使用 Perl 编写脚本?或不?如果是,如何?

NOTE: if it is possible without any modules please say the solution without any module, and if not, okay no problem

但是,非常感谢你。

如果您不担心有点延迟,您可以尝试 selectalarm 来尝试处理用户输入。

使用 select 您可以处理 STDIN 并使用 alarm 您可以等待几秒钟或更短的时间来等待用户输入。

#!/usr/bin/env perl 

use common::sense;

use IO::Select;

my $sel = IO::Select->new();
$sel->add( \*STDIN );

$|++;

my $running = 1;

while ($running) {

    eval {

        local $SIG{ALRM} = sub { die 'Time Out'; };

        alarm 0.5;

        if ( $sel->can_read(0) ) {

            my $input = <STDIN>;

            chomp $input;

            print "STDIN > $input\n";

            $running = 0;

        }
    };

    if ( !$@ ) {

        select( undef, undef, undef, 0.5 );

        print ".";

    }
}

print "\nEnd Of Script\n";

我告诉过你尝试使用 Term::ReadKey :-)

开始吧:

!/usr/bin/env perl 

use common::sense;
use Term::ReadKey;

my $running = 1;
my $key;

while ($running) {
    ReadMode 4;    # Turn off controls keys
    while ( not defined( $key = ReadKey(-1) ) ) {

        select( undef, undef, undef, 0.5 );

        print '.';

    }
    print "\nSTDIN> $key\n";
    ReadMode 0;  

}

print "\nEnd Of Script\n";

现在您只需处理 quit 或 int 等信号即可退出循环,但使用它您可以捕获输入并执行任何您想做的事情。

这对你有用

use 5.010;
use strict;
use Term::ReadKey;

ReadMode 4; # It will turn off controls keys (eg. Ctrl+c)

my $key; 

# It will create a child so from here two processes will run.
# So for parent process fork() will return child process id
# And for child process fork() will return 0 id

my $pid = fork(); 

# This if block will execute by the child process and not by 
# parent because for child $pid is 0     

if(not $pid){

   while(1){

        # Do your main task here
        say "hi I'm sub process and contains the main task";
        sleep 2;
    }
}

# Parent will skip if block and will follow the following code
while (1) {

   $key = ReadKey(-1); # ReadKey(-1) will perform a non-blocked read

   if($key eq 'q'){    # if key pressed is 'q'

      `kill -9 $pid`;   # then if will run shell command kill and kill
                        # the child process
       ReadMode 0;      # Restore original settings for tty.

       exit;            # Finally exit from script

    } elsif( $key eq 'h' ) {

         say "Hey! you pressed $key key for help";
    } elsif( $key ne '' ) {

        say "Hey! You pressed $key";
    }
}

参考文献:

假设你的程序有一个中央循环,或者如果你可以简单地将键盘检查放入处理中,你最好使用 Term::ReadKey 而不是尝试放入 fork 并处理必要的 inter-process 交流

调用 ReadKey(-1) 将进行 non-blocking 读取,如果按下某个键,则将 return 读取单个字符,否则 undef。 (您可以提供第二个参数,即要使用的 IO 通道,但它将默认为 STDIN。)

我建议你运行这个例子。我使用 sleep 1 作为循环处理的虚拟对象

use strict;
use warnings 'all';
use feature 'say';

use Term::ReadKey;

my $n;

while () {

    my $key = ReadKey(-1);

    say "key $key entered" if defined $key;

    sleep 1;

    say ++$n;
}