The (modified) script is running 'less', so you piping to less as well just gets in the way. If you want to prevent the script from running 'less' sometimes, then you'd need to implement a command-line option or similar to disable that feature.
To be extra clear, just run the modified script by itself. Don't type "| less" as then you end up with two instances of 'less' running at the same time (and, more importantly, "| less" still gets in the way of you entering information at the prompts, just like before).
You might want to tell 'less' to (by default) not prompt if no more than a screen-full of text was output before the next prompt ('less -F'). 'less -E' might also be desirable since you'll have multiple "ends" to have to get past in this case (or you might find that either of those make some cases a bit confusing).
sub prompt {
my( $prompt, $validator, $reprompt ) = @_;
my $interactive = -t STDOUT && -t STDIN;
# Close out previous pager (if any):
if( $interactive ) {
select STDOUT;
close PAGER;
}
# Prompt the user for a response:
my $response;
while( 1 ) {
print STDERR $prompt
if $interactive;
$response = <STDIN>;
die "End of input.\n"
if ! defined $response;
chomp $response;
last
if ! $interactive
|| ! $validator
|| $validator->( $response );
$prompt = $reprompt
if $reprompt;
}
# Run output (until next prompt) through pager:
if( $interactive ) {
my $pager = $ENV{PAGER} || 'less -EF';
open PAGER, '|-', $pager
or die "Can't run $pager: $!\n";
select PAGER;
}
return $response;
}
The new version above makes the 2nd and 3rd arguments optional.
Yes, the code:
last
if $validator->( $response );
means that $validator needed to be a reference to a subroutine and that the subroutine would be passed what the user entered (minus the newline) and should return a false value only if the entered response was not acceptable. Not providing that makes it pointless to provide $reprompt since input would never be declared invalid so reprompting would never happen.
(Update: For example:
prompt(
"Knarfle the garthog? ",
sub { shift(@_) =~ /^[yn]/i },
"Yes or no? ",
);
)
I should probably test this code, but I haven't. (I probably will later.)
But I'll repeat that, if you are printing output other than via 'print' (without a file handle argument), then you'll probably want to do the extra work to redirect STDOUT to the pager, rather than just the trivial step of using select like I did.
The new version also notices if you have either piped in a file or piped the output to a command (like 'less') or a file and doesn't bother writing out prompts or trying to run 'less' in such cases (since such efforts would be mostly pointless).
Update: I just realized that any output before the first prompt is not piped to an instance of a pager. I'll have to fix that at some point and post an updated version. This seems like exactly the type of thing one could find on CPAN, but I haven't previously run into such (and haven't searched for such yet).
Update: (late but tiny) Term::DBPrompt provides this type of functionality but rather less conveniently. Just FYI. I didn't find anything else that came close.
|