Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

No interactivity (prompt) after reading from pipe

by svenXY (Deacon)
on Nov 18, 2005 at 14:13 UTC ( [id://509786]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Fellow Monks,
probably an easy one, but I just can't figure it out:
I have a script that
  • reads from a pipe
  • has getopts options
  • is supposed to ask a decision from the user
Here's the code:
#!/usr/bin/perl -w use strict; use Getopt::Std; my $what; $| = 1; my @hosts; my %opts; while (<STDIN>) { chomp; push(@hosts, $_); } getopts(':dw', \%opts); $what .= ' bla' if $opts{'d'}; $what .= ' blabla' if $opts{'w'}; print "OK? [Y|n]>\n"; my $yesno = <STDIN>; chomp $yesno; exit 1 if $yesno =~ /^[nN]$/; print "Did not stop, sorry!\n";
However, running it looks like this:
$ echo -e "aaa\nbbb\nccc\n" | script.pl -d OK? [Y|n]> Use of uninitialized value in scalar chomp at script.pl line 23, <STDI +N> line 4. Use of uninitialized value in pattern match (m//) at script.pl line 24 +, <STDIN> line 4. Did not stop, sorry!
and does not stop to ask for input. I already tried different stuff and also supersearched, but to no avail.
Any hints greatly appreciated!

Regards,
svenXY

Replies are listed 'Best First'.
Re: No interactivity (prompt) after reading from pipe
by Perl Mouse (Chaplain) on Nov 18, 2005 at 14:52 UTC
    You could open the terminal, and read from the terminal instead of STDIN (which is connected to the pipe). Under Unix:
    open my $kb, "<", "/dev/tty" or die; while (<$kb>) { ... }
    Perl --((8:>*
Re: No interactivity (prompt) after reading from pipe
by fizbin (Chaplain) on Nov 18, 2005 at 15:08 UTC

    What everyone else has said so far is right - if you are reading from a pipe, then you cannot simply read from standard input again to read from the terminal.

    However, this does not mean that all is lost. On many POSIX systems, you can find the name of the controlling terminal with POSIX::ctermid(); and then open and read from that.

    #!/usr/bin/perl -w use strict; use Getopt::Std; use POSIX qw//; my $what; $| = 1; my @hosts; my %opts; while (<STDIN>) { chomp; push(@hosts, $_); } getopts(':dw', \%opts); $what .= ' bla' if $opts{'d'}; $what .= ' blabla' if $opts{'w'}; my $cterm = POSIX::ctermid(); if (! $cterm) {die "No controlling terminal to read prompt from!";} if (! open(CTERM, '<', $cterm)) { die "Couldn't open controlling terminal $cterm: $!"; } print "OK? [Y|n]>\n"; my $yesno = <CTERM>; chomp $yesno; exit 1 if $yesno =~ /^[nN]$/; print "Did not stop, sorry!\n";

    Yes, I could have used STDIN there the second time, but I didn't so as to keep it clear where you were reading what from.

    --
    @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/
Re: No interactivity (prompt) after reading from pipe
by larryk (Friar) on Nov 18, 2005 at 14:32 UTC
    I guess it's because you're piping stuff to STDIN. That will finish with an EOF (so that your while loop can complete) and so when you get to trying to read from STDIN again for user input, perl thinks STDIN is at EOF and doesn't read any more.

    Try putting this in before your <STDIN>:

    eof(STDIN) and print "This ain't gonna work\n";

    Question is... how do you reset the EOF on STDIN?

       larryk                                          
    perl -le "s,,reverse killer,e,y,rifle,lycra,,print"
    
      Hi,
      OK, that is indeed the case.
      Can I close and reopen STDIN somehow?
      Regards,
      svenXY
        Have a look at seek, pp. 779-780 in Programming Perl, 3rd edition.
Re: No interactivity (prompt) after reading from pipe
by ptum (Priest) on Nov 18, 2005 at 14:41 UTC
    So, it seems to me you need to make up your mind, do you want to read from a pipe, or do you want to read from a user? Your while <STDIN> consumes all of the pipe content, and then there is nothing left on STDIN. By the time you print your OK? prompt, STDIN is already at EOF, so it skips on past any intended user input.
Re: No interactivity (prompt) after reading from pipe
by Aristotle (Chancellor) on Nov 18, 2005 at 14:50 UTC

    I don’t know how to do this, but since noone else has told you what you need to do, I hope this pointer helps anyway: what you need is to find the controlling terminal and write to/read from it to prompt the user.

    Makeshifts last the longest.

Re: No interactivity (prompt) after reading from pipe
by svenXY (Deacon) on Nov 18, 2005 at 15:03 UTC
    ++Perl Mouse!!!
    this one works as expected:
    #!/usr/bin/perl -w use strict; use Getopt::Std; my $what; $| = 1; my @hosts; my %opts; while (<STDIN>) { chomp; push(@hosts, $_); } getopts(':dw', \%opts); $what .= ' bla' if $opts{'d'}; $what .= ' blabla' if $opts{'w'}; print "OK? [Y|n]>\n"; open my $kb, "<", "/dev/tty" or die; while (<$kb>) { exit 1 if /^[nN]$/; last; } print "Did not stop, sorry!\n";
    Running it now looks like this:
    $ echo -e "aaa\nbbb\nccc\n" | script.pl -d OK? [Y|n]> y Did not stop, sorry! $ echo -e "aaa\nbbb\nccc\n" | script.pl -d OK? [Y|n]> n
    Thanks a lot for solving this!
    Regards,
    svenXY

    ptum, I wasn't able to do it with seek - just out of curiosity - how would you do it?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://509786]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (5)
As of 2024-04-23 09:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found