I've decided to provide a near-exact reimplementation in Perl.
The main differences are that you don't specify the "looping" variable (it uses $_ instead), and the code block comes before the list of choices. This just seems more perlish.
One of the fun things about this implementation is that, just like the ksh select statement, it temporarily owns stdin; to exit the loop, you hit ^D (or ^Z on DOS; or as appropriate for your system/terminal).
sub ksh_select(&@) {
my $cr = shift;
my $prompt = $ENV{'PS3'} || '#? ';
local *ARGV;
local $| = 1;
local $_;
while (1) {
for my $i ( 0 .. $#_ ) {
print STDOUT $i+1, ") $_[$i]\n";
}
print STDOUT $prompt;
$_ = <>;
defined $_ or return;
chomp;
$cr->( $_ );
}
}
A simple example usage:
ksh_select { print "You chose $_\n" } qw( foo bar quux );
A more realistic example:
# in this example, the user has choices to navigate around some struct
+ure.
my %dispatch = (
First => \&goto_first,
Prev => \&goto_prev,
Next => \&goto_next,
Last => \&goto_last,
);
my @menu = qw( First Prev Next Last );
ksh_select {
defined $menu[$_]
? $dispatch{$menu[$_]}->()
: warn "Selection out of range!\n";
} @menu;