Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

portable way of locating an executable (like which)

71 views
Skip to first unread message

Gelonida N

unread,
Sep 20, 2012, 5:06:46 PM9/20/12
to pytho...@python.org
I'd like to implement the equivalent functionality of the unix command
/usr/bin/which

The function should work under Linux and under windows.

Did anybody already implement such a function.
If not, is there a portable way of splitting the environment variable PATH?

Thanks for any sugestions


Mark Lawrence

unread,
Sep 20, 2012, 5:47:11 PM9/20/12
to pytho...@python.org
On 20/09/2012 22:06, Gelonida N wrote:
> I'd like to implement the equivalent functionality of the unix command
> /usr/bin/which
>
> The function should work under Linux and under windows.
>
> Did anybody already implement such a function.

Searching found nothing obvious to me :(

> If not, is there a portable way of splitting the environment variable PATH?

With os.sep ?

>
> Thanks for any sugestions
>
>

--
Cheers.

Mark Lawrence.

Chris Angelico

unread,
Sep 20, 2012, 6:21:27 PM9/20/12
to pytho...@python.org
On Fri, Sep 21, 2012 at 7:47 AM, Mark Lawrence <bream...@yahoo.co.uk> wrote:
> On 20/09/2012 22:06, Gelonida N wrote:
>>
>> I'd like to implement the equivalent functionality of the unix command
>> /usr/bin/which
>>
>> The function should work under Linux and under windows.
>>
>> Did anybody already implement such a function.
>
> Searching found nothing obvious to me :(
>
>> If not, is there a portable way of splitting the environment variable
>> PATH?
> With os.sep ?

os.sep is the directory separator, but os.pathsep may be what you
want. Between that and os.getenv('path') you can at least get the
directories. Then on Windows, you also need to check out
os.getenv('pathext') and split _that_ on the semicolon, and try each
of those as a file extension. I'm not sure whether or not Windows will
add extensions from pathext if one is given on the command line - for
instance, if typing "foo.exe" will search for "foo.exe.bat" - but the
basics are there.

Alternatively, there may be a Win32 API funct5ion that does this.
Would be worth a look.

ChrisA

Ian Kelly

unread,
Sep 20, 2012, 6:32:42 PM9/20/12
to Python
On Thu, Sep 20, 2012 at 4:21 PM, Chris Angelico <ros...@gmail.com> wrote:
> os.sep is the directory separator, but os.pathsep may be what you
> want. Between that and os.getenv('path') you can at least get the
> directories. Then on Windows, you also need to check out
> os.getenv('pathext') and split _that_ on the semicolon, and try each
> of those as a file extension. I'm not sure whether or not Windows will
> add extensions from pathext if one is given on the command line - for
> instance, if typing "foo.exe" will search for "foo.exe.bat" - but the
> basics are there.

Easy enough to test:

C:\>echo echo hello! > foo.exe.bat

C:\>foo.exe
hello!

Yup, it does. It looks like it tries it without the extension first, though:

C:\>copy c:\windows\notepad.exe foo.exe
1 file(s) copied.

C:\>foo.exe
[starts notepad]

Chris Angelico

unread,
Sep 20, 2012, 7:04:06 PM9/20/12
to pytho...@python.org
Well, at least it's consistent. Makes your PATH extremely sensitive,
though, easy for anyone to inject executables into it. But then, you
can already do that by putting them in the current directory, so
that's not really any different.

Jason's solution looks fine apart from the PATHEXT requirement, so if
you know you have the full filename and you don't care if the actual
command interpreter will do exactly the same, that'll do you fine.

Is this something that might want to be a function in the os module?
Particularly so if, as I suspect there might be, there's a Win32 API
function that precisely replicates the behaviour of executable
invocation. A while since I've done much Windows programming but I
think there's a SearchPath function?

ChrisA

Gelonida N

unread,
Sep 20, 2012, 7:07:08 PM9/20/12
to pytho...@python.org
On 09/21/2012 12:21 AM, Chris Angelico wrote:
> On Fri, Sep 21, 2012 at 7:47 AM, Mark Lawrence <bream...@yahoo.co.uk> wrote:
>> On 20/09/2012 22:06, Gelonida N wrote:
>>>
>>> I'd like to implement the equivalent functionality of the unix command
>>> /usr/bin/which
>>>
>>> The function should work under Linux and under windows.
>>>
>>> Did anybody already implement such a function.
>>
>> Searching found nothing obvious to me :(

I was afraid so, but wanted to be sure
>>
>>> If not, is there a portable way of splitting the environment variable
>>> PATH?
>> With os.sep ?
>
> os.sep is the directory separator, but os.pathsep may be what you
> want.

Thanks,
os.pathsep was the missing piece for portably splitting the searchpath

> Between that and os.getenv('path') you can at least get the
> directories. Then on Windows, you also need to check out
> os.getenv('pathext') and split _that_ on the semicolon, and try each
> of those as a file extension. I'm not sure whether or not Windows will
> add extensions from pathext if one is given on the command line - for
> instance, if typing "foo.exe" will search for "foo.exe.bat" - but the
> basics are there.
>
For what I am doing I can even skip trying the pathexts, the ext is
already given, but good to know :-)


> Alternatively, there may be a Win32 API funct5ion that does this.
> Would be worth a look.

Yeah true, but ideally I'd like to avoid platform detection and
just have a generic function.




Gelonida N

unread,
Sep 20, 2012, 7:15:02 PM9/20/12
to pytho...@python.org
On 09/21/2012 12:04 AM, Jason Swails wrote:
>
Thanks a lot Jason,


> I've used the following in programs I write:
>
> def which(program):
> 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.getenv("PATH").split(os.pathsep):
> exe_file = os.path.join(path, program)
> if is_exe(exe_file):
> return exe_file
> return None
>
> IIRC, I adapted it from StackOverflow. I know it works on Linux and Mac
> OS X, but not sure about windows (since I don't know if PATH works the
> same way there).

I'll try it, the script looks reasonably portable (using os.pathsep)
to really replicate which I had probably to add os.getenv('pathext')
as Chris mentioned.
However for my current use case this is not necessarily required.
>
> HTH,
> Jason
>
>
>


Mark Lawrence

unread,
Sep 20, 2012, 7:46:48 PM9/20/12
to pytho...@python.org

Nobody

unread,
Sep 20, 2012, 7:59:53 PM9/20/12
to
On Thu, 20 Sep 2012 23:06:46 +0200, Gelonida N wrote:

> I'd like to implement the equivalent functionality of the unix command
> /usr/bin/which
>
> The function should work under Linux and under windows.

Note that "which" attempts to emulate the behaviour of execvp() etc. The
exec(3) manpage will explain the precise algorithm used (e.g. they skip
files for which the process lacks execute permission).

Also, note that the shell has built-in commands, functions, and aliases in
addition to programs. The "type" built-in command performs a similar
function to "which" but using the shell's semantics. On some systems,
the default configuration may alias "which" to "type".

On Windows, there's a host of different "execute program" interface, all
with subtly different semantics: which extensions they will run, which
extensions can be omitted, which paths are used (e.g. %PATH%, paths
from the registry, current directory).

Dave Angel

unread,
Sep 20, 2012, 10:31:17 PM9/20/12
to Jason Swails, Gelonida N, pytho...@python.org
On 09/20/2012 06:04 PM, Jason Swails wrote:
> On Thu, Sep 20, 2012 at 5:06 PM, Gelonida N <gelo...@gmail.com> wrote:
>
>> I'd like to implement the equivalent functionality of the unix command
>> /usr/bin/which
>>
>> The function should work under Linux and under windows.
>>
>> Did anybody already implement such a function.
>> If not, is there a portable way of splitting the environment variable PATH?
>>
> I've used the following in programs I write:
>
> def which(program):
> 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.getenv("PATH").split(os.pathsep):
> exe_file = os.path.join(path, program)
> if is_exe(exe_file):
> return exe_file
> return None
>
> IIRC, I adapted it from StackOverflow. I know it works on Linux and Mac OS
> X, but not sure about windows (since I don't know if PATH works the same
> way there).
>

I don't have a Windows machine set up right now, but I believe there are
two more directories to search, besides the ones described in the PATH
variable.

One is the current directory, and the other is the Windows directory
(maybe also the xxx/system32 or something).

They don't have analogues in Linux or Mac, as far as I know.

--

DaveA

Andrew Berg

unread,
Sep 20, 2012, 10:57:14 PM9/20/12
to comp.lang.python
On 2012.09.20 21:31, Dave Angel wrote:
> I don't have a Windows machine set up right now, but I believe there are
> two more directories to search, besides the ones described in the PATH
> variable.
>
> One is the current directory, and the other is the Windows directory
> (maybe also the xxx/system32 or something).
Those system directories are in the path by default.

--
CPython 3.3.0rc2 | Windows NT 6.1.7601.17835

Tarek Ziadé

unread,
Sep 21, 2012, 4:12:29 AM9/21/12
to pytho...@python.org
You can also look at shutil.which

http://hg.python.org/cpython/file/aa153b827d17/Lib/shutil.py#l974


Mmmm I wonder why it's removed in the last revs..

Hans Mulder

unread,
Sep 21, 2012, 6:13:48 AM9/21/12
to
On 21/09/12 04:31:17, Dave Angel wrote:
> On 09/20/2012 06:04 PM, Jason Swails wrote:
>> On Thu, Sep 20, 2012 at 5:06 PM, Gelonida N <gelo...@gmail.com> wrote:
>>
>>> I'd like to implement the equivalent functionality of the unix command
>>> /usr/bin/which
>>>
>>> The function should work under Linux and under windows.
>>>
>>> Did anybody already implement such a function.
>>> If not, is there a portable way of splitting the environment variable PATH?
>>>
>> I've used the following in programs I write:
>>
>> def which(program):
>> 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.getenv("PATH").split(os.pathsep):

On Posix systems, you need to insert at this point:

if not path:
path = "."

>> exe_file = os.path.join(path, program)
>> if is_exe(exe_file):
>> return exe_file
>> return None
>>
>> IIRC, I adapted it from StackOverflow. I know it works on Linux and Mac OS
>> X, but not sure about windows (since I don't know if PATH works the same
>> way there).
>
> I don't have a Windows machine set up right now, but I believe there are
> two more directories to search, besides the ones described in the PATH
> variable.
>
> One is the current directory, and the other is the Windows directory
> (maybe also the xxx/system32 or something).
>
> They don't have analogues in Linux or Mac, as far as I know.

On Posix system (inlcuding Linux and Mac OS X), the current
directory is not searched by default. If there's an empty
string in os.getenv("PATH").split(os.pathsep), then the
current directory will be searched at that point in the part.


Hope this helps,

-- HansM



Ramchandra Apte

unread,
Sep 22, 2012, 11:55:46 PM9/22/12
to pytho...@python.org
shutil.which does this in Python 3.3: http://docs.python.org/dev/library/shutil.html#shutil.which
You can copy the code to support older Python versions.

Ramchandra Apte

unread,
Sep 22, 2012, 11:55:46 PM9/22/12
to comp.lan...@googlegroups.com, pytho...@python.org
On Friday, 21 September 2012 02:37:01 UTC+5:30, gelonida wrote:
0 new messages