`which` (for Windows) in pure perl
bart
created: 2006-04-22 17:32:45
Sometimes you need to find the absolute path to an executable program, just like the command line utility [http://unixhelp.ed.ac.uk/CGI/man-cgi?which|which] does on Unix. Here's a bit of code that searches PATH for the executable trying various extensions (and without one, in case you already appended one yourself), and populates an array with it.
# input:
my $f = 'perl';  # for example

# output:
my @exec;

{
    use File::Spec;
    my @ext = split /;/, $ENV{PATHEXT} || '.exe;.com;.bat';
    foreach my $p (File::Spec->path) {
        push @exec, grep { -f and -x } map File::Spec->catfile($p, "$f$_"), '', @ext;
        # You may leave the loop when something is found, if you only care about the first
    }
    @exec or die "Can't find executable $f";
}

# Show result:
{
    local $\ = "\n";
    print for @exec;
}
Re: `which` (for Windows) in pure perl
created: 2006-04-22 17:44:18
File::Which provides a portable implementation for a which function.
Re^2: `which` (for Windows) in pure perl
created: 2006-04-23 17:09:16
Mine is, essentially, 5 lines of code. A snippet. You can reduce that even more if you don't care about other extensions than the default qw(.exe .com .bat) (the others might not even work). Do you really need a module for that?
use File::Spec;
my @exec = map { my $p = $_; grep { -f and -x } map File::Spec->catfile($p, "$f$_"), '', qw(.exe .com .bat) } File::Spec->path
  or die "Can't find executable $f";

Oh, and I found a bug in the module:

#!/usr/bin/perl -wl
use File::Which;
open OUT, '>complexe'; close OUT;
print for which('complexe');
which prints out
.\complexe
The author has forgotten to use [quotemeta]. The file name matches /.exe$/, but still, it's not a program file name.
Re^3: `which` (for Windows) in pure perl
created: 2006-04-23 17:20:41
In the expression:
grep { -f and -x }
You only need to stat the file once:
grep { -f and -x _ }

Re^3: `which` (for Windows) in pure perl (bugs)
tye
created: 2006-04-24 10:53:45

Your code also looks for 'complexe' (no extension) when asked to look for 'complexe' (because of the empty string you pass to map) so you have the same 'bug'. Your code doesn't output 'complexe' because '-x' compares the extension (again) for you.

You also suffer from a bug (or perhaps interface contract dispute) in (at least some versions of) File::Spec in that '.' is not returned from File::Spec->path() even though it is unconditionally searched first even if it isn't present in $ENV{PATH}. Perhaps File::Spec->path() is meant to (as documented) only return what is set in $ENV{PATH} rather than returning what would be more useful, the list of directories that would be searched when a command is entered. I'd rather this bug be fixed by updating File::Spec's implementation and documentation, however.

- tye        

perlmonks.org content © perlmonks.org and bart, jwkrahn, salva, tye

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03