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
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>) {
...
}
| [reply] [d/l] |
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@/
| [reply] [d/l] [select] |
Re: No interactivity (prompt) after reading from pipe
by larryk (Friar) on Nov 18, 2005 at 14:32 UTC
|
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"
| [reply] [d/l] |
|
Hi,
OK, that is indeed the case.
Can I close and reopen STDIN somehow?
Regards,
svenXY
| [reply] |
|
Have a look at seek, pp. 779-780 in Programming Perl, 3rd edition.
| [reply] |
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. | [reply] |
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.
| [reply] |
Re: No interactivity (prompt) after reading from pipe
by svenXY (Deacon) on Nov 18, 2005 at 15:03 UTC
|
#!/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? | [reply] [d/l] [select] |
|
|