tags:

views:

3670

answers:

10

In python, is there a portable and simple way to test if an executable program exists?

By simple I mean something like the 'which' command which would be just perfect. I don't want to search PATH manually or something involving trying to execute it with Popen & al and see if it fails (that's what I'm doing now, but imagine it's launchmissiles)

EDIT: The answer is 'No', from the different posts, I just have to search path manually ans use Jay's answer (sorry for the bad formulation about 'which' which I understand, but I thought maybe there's something in os.path that does that though named strangely).

A: 

you can tell if a file exists with the os module. an executable in particular seems quite unportable considering lots of things are executable on nix that aren't on windows and vice versa.

Dustin Getz
+16  A: 

Easiest way I can think of:

def which(program):
    import os
    def is_exe(fpath):
        return os.path.exists(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None

Edit: Updated code sample to include logic for handling case where provided argument is already a full path to the executable, i.e. "which /bin/ls". This mimics the behavior of the UNIX 'which' command.

Jay
Thanks Jay, I accept your answer, though for me it answers my question by the negative. No such function exists in the libs, I just have to write it (I admit my formulation was not clear enough in the fact that I know what which does).
Piotr Lesnicki
Jay, if you complete your answer according to mine (to have complete 'w') so I can remove mine.
Piotr Lesnicki
Ah, that makes more sense, gotcha now.
Jay
@Piotr - updated the code for cases with full paths provided as argument
Jay
I think you should use os.path.isfile(fpath) instead of: os.path.exists(fpath)
Giampaolo Rodolà
A: 

It would seem the obvious choice is "which", parsing the results via popen, but you could simulate it otherwise using the os class. In pseudopython, it would look like this:

for each element r in path:
    for each file f in directory p:
        if f is executable:
           return True
Charlie Martin
I would be careful about running a "which" command using os.exec or something like that. Not only is it often slow (if performance is any kind of concern), but if you're using a variable as part of your exec string, security becomes a concern. Somebody could sneak in a "rm -rf /".
Parappa
Which, since we'd be using the os.popen function to run a which command created by the program, doesn't actually apply, no?
Charlie Martin
Thanks, but I'm not sure if 'which' exists on windows and the likes. I wanted essentially to know if something fancy exists in the standart lib
Piotr Lesnicki
+4  A: 

See os.path module for some useful functions on pathnames. To check if an existing file is executable, use os.access(path, mode), with the os.X_OK mode.

os.X_OK

Value to include in the mode parameter of access() to determine if path can be executed.

EDIT: The suggested which() implementations are missing one clue - using os.path.join() to build full file names.

gimel
Thanks, gimel, so basically I have my answer: no such function exists, I must do It manually.
Piotr Lesnicki
You are in the right direction. Look at os.path.join()
gimel
right, I ise it usually, never copy-paste blindly..
Piotr Lesnicki
A: 

So basically you want to find a file in mounted filesystem (not necessarily in PATH directories only) and check if it is executable. This translates to following plan:

  • enumerate all files in locally mounted filesystems
  • match results with name pattern
  • for each file found check if it is executable

I'd say, doing this in a portable way will require lots of computing power and time. Is it really what you need?

zgoda
+1  A: 

Just remember to specify the file extension on windows. Otherwise, you have to write a much complicated is_exe for windows using PATHEXT environment variable. You may just want to use FindPath.

OTOH, why are you even bothering to search for the executable? The operating system will do it for you as part of popen call & will raise an exception if the executable is not found. All you need to do is catch the correct exception for given OS. Note that on Windows, subprocess.Popen(exe, shell=True) will fail silently if exe is not found.

Suraj Barkale
A: 

There is a which.py script in a standard Python distribution (e.g. on Windows '\PythonXX\Tools\Scripts\which.py').

EDIT: which.py depends on ls therefore it is not cross-platform.

J.F. Sebastian
A: 

If you have bash and a function sh (subprocess.Popen( ... ).communicate() ),
use the bash builtin type:

type -p ls  =>  /bin/ls
type -p nonesuch  =>  ""
Denis
+1  A: 

None of previous examples do work on all platforms. Usually they fail to work on Windows because you can execute without the file extension and that you can register new extension. For example on Windows if python is well installed it's enough to execute 'file.py' and it will work.

The only valid and portable solution I had was to execute the command and see error code. Any decent executable should have a set of calling parameters that will do nothing.

Sorin Sbarnea
A: 

An important question is "Why do you need to test if executable exist?" Maybe you don't? ;-)

Recently I needed this functionality to launch viewer for PNG file. I wanted to iterate over some predefined viewers and run the first that exists. Fortunately, I came across os.startfile. It's much better! Simple, portable and uses the default viewer on the system:

>>> os.startfile('yourfile.png')

Update: I was wrong about os.startfile being portable... It's Windows only. On Mac you have to run open command. And xdg_open on Unix. There's a Python issue on adding Mac and Unix support for os.startfile.

ash