yoda54 has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks, I'd like run a script that will listen for input and if nothing is entered in a given amount of time, it will run some other function and continue presenting the user with a prompt. For some reason my code is not working. Can anyone provide any hints? Thanks much!
#!/usr/bin/perl -w $SIG{ALRM} = sub { command() }; command(); if ($@) { if ($@ =~ /timeout/) { command(); } else { alarm(0); # clear the still-pending alarm die; # propagate unexpected exception } } sub command { my $date = `date`; chomp($date); alarm(5); print "\n"; print "prompt $date > "; <>; alarm(0); }

Replies are listed 'Best First'.
Re: Timeout on STDIN
by VSarkiss (Monsignor) on Jul 19, 2004 at 20:34 UTC

    Signal handling varies greatly from OS to OS, and you don't mention what you're running on, but I'll take a stab at it.

    The problem is that you're trying to call the routine from the signal handler. In turn, that routine expects to continue to receive SIGALRM, although in most cases, the signal won't be delivered while you're in the handler (otherwise the handler might get called recursively).

    A better strategy would be to let the handler throw an exception, and then let the outer loop control the logic. Here's a modification of your program that does what (I think ;-) you want.

    #!/usr/bin/perl -w $SIG{ALRM} = sub { die "timeout"; }; while (1) { eval { command(); }; if ($@) { if ($@ =~ /timeout/) { redo; } else { alarm(0); die; } } else { last; } } print "Done\n"; sub command { my $date = `date`; chomp($date); alarm(5); print "\n"; print "prompt $date > "; <>; alarm(0); }

    HTH. The usual disclaimers apply: I'm not sure exactly what behavior you wanted, nor what OS you're on, yada, yada, yada.

Re: Timeout on STDIN
by BUU (Prior) on Jul 19, 2004 at 20:38 UTC
    I'm not sure exactly, but I managed to get down to this:
    $SIG{ALRM} = sub { die };alarm(2);<>;
    Which just hangs on win32 but works fine on linux. So I'm blaming windows =]
Re: Timeout on STDIN
by gmpassos (Priest) on Jul 20, 2004 at 00:29 UTC
    Take a look in IO::Select, where you can test with a timeout if you have data to read in an IO Handler.

    But note that for Win32 IO::Select won't work for STDIN. ;-/

    Graciliano M. P.
    "Creativity is the expression of the liberty".

Re: Timeout on STDIN
by zentara (Cardinal) on Jul 20, 2004 at 12:54 UTC
    Heres another snippet.
    #!/usr/bin/perl use strict; use warnings; use Term::ReadKey; sub timed_input { my $end_time = time + shift; my $string; do { my $key = ReadKey(1); $string .= $key if defined $key; } while (time < $end_time); return $string }; my @words = split ' ', timed_input(10); print "@words\n";

    I'm not really a human, but I play one on earth. flash japh

      I am trying zentaras snippet, and failing...

      my perl script got started as a child process, so the parent communicates via STDIN to my script. There is no real keyboard involved. Unfortunately I'm not really up to speed on terminals and tty. I'm wondering if Term::ReadKey should work in that case.

      This is a win32 application

      sub get_stdin_w_timeout { ######!/usr/bin/perl #got from zentara on perl monks in response to Timeout on STDIN #modifying to use ReadKey to get first key and then <STDIN> to get t +he rest of the line #this function assumes that once there is some input on stdin, #the rest of the line is available too use strict; use warnings; use Term::ReadKey; my $timeout_in_sec=shift; my $end_time = time + $timeout_in_sec; my $key=""; do { my $key = ReadKey(1); if (defined $key) { #not sure if I need to concatenate $key on the front of <STDIN> return $key. <STDIN>; } } while (time < $end_time ); return "!ERROR!:Timed out waiting on input after ${timeout_in_sec}s\ +n"; }

      when i run this like this

      $plibMsg=&get_stdin_w_timeout(5);#<STDIN>;

      I always get the Timed out message