Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Re^3: Piping a script with prompts into less (edit script)

by tye (Sage)
on Oct 19, 2012 at 02:37 UTC ( #999848=note: print w/replies, xml ) Need Help??

in reply to Re^2: Pipping a script with prompts into less (edit script)
in thread Pipping a script with prompts into less

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.

- tye        

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://999848]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (6)
As of 2018-05-24 17:58 GMT
Find Nodes?
    Voting Booth?