exec can be given arrays, so you don't need to quote arguments.
to get the pipe open behavior you can pipeopen ls, and then exec the pager:
open STDIN, "-|", ...;
exec @pager;
FYI, that is how the shells do it: they create the pipeline descriptors, fork off children for the processes, dup the filedescriptors to stdin/stdout as appropriate, and then exec the subproccesses.
If you insist on quoting and concatenating there are cpan modules to do this more safely.
map { } in void context is silly:
$_ = qq{"$_"} for @ARGV;
To check if you have less, don't make assumptions based on the platforms. Instead:
use File::Which;
my $pager = which("less") || which("more") || die "no pager";
Lastly, all of this could be completely superceded with a shell alias =)
|