Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

`which` (for Windows) in pure perl

by bart (Canon)
on Apr 22, 2006 at 21:32 UTC ( #545096=snippet: print w/replies, xml ) Need Help??
Description: Sometimes you need to find the absolute path to an executable program, just like the command line utility 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.

p.s. Apparently -x doesn't work for DLL files. Not so nice.

# input:
# my $f = 'perl';  # for example
# via command line:
my $f = shift;

# 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;
Replies are listed 'Best First'.
Re: `which` (for Windows) in pure perl
by salva (Abbot) on Apr 22, 2006 at 21:44 UTC
    File::Which provides a portable implementation for a which function.
      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->catfil +e($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
      The author has forgotten to use quotemeta. The file name matches /.exe$/, but still, it's not a program file name.
        In the expression:
        grep { -f and -x }
        You only need to stat the file once:
        grep { -f and -x _ }

        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        

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (5)
As of 2018-06-22 23:45 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (124 votes). Check out past polls.