python library call equivalent to `which' command

D

destroooooy

Hi,
I'm looking for a Python library function that provides the same
functionality as the `which' command--namely, search the $PATH
variable for a given string and see if it exists anywhere within. I
currently examine the output from `which' itself, but I would like
something more portable. I looked through the `os' and `os.path'
modules but I didn't find anything.

TIA

Craig
 
T

Tim Pinkawa

Hi,
I'm looking for a Python library function that provides the same
functionality as the `which' command--namely, search the $PATH
variable for a given string and see if it exists anywhere within. I
currently examine the output from `which' itself, but I would like
something more portable. I looked through the `os' and `os.path'
modules but I didn't find anything.

This works on POSIX systems. Windows uses semicolons to separate paths
rather than colons so that would need to be taken into account when
running on Windows. This also doesn't recognize shell built-ins, only
real binaries.

import os

def which(file):
for path in os.environ["PATH"].split(":"):
if file in os.listdir(path):
print "%s/%s" % (path, file)
/bin/ls
 
T

Tim Golden

Tim said:
Hi,
I'm looking for a Python library function that provides the same
functionality as the `which' command--namely, search the $PATH
variable for a given string and see if it exists anywhere within. I
currently examine the output from `which' itself, but I would like
something more portable. I looked through the `os' and `os.path'
modules but I didn't find anything.

This works on POSIX systems. Windows uses semicolons to separate paths
rather than colons so that would need to be taken into account when
running on Windows. This also doesn't recognize shell built-ins, only
real binaries.

import os

def which(file):
for path in os.environ["PATH"].split(":"):
if file in os.listdir(path):
print "%s/%s" % (path, file)
/bin/ls

There's a "which.py" in the tools directory included in
the Python distribution. On windows, that's
c:\python26\tools\scripts; don't know where to look
on Linux.

Don't know how good it is as I -- like many, I suspect --
wrote my own, which in my case is Windows-specific.

TJG
 
N

Nobody

This works on POSIX systems. Windows uses semicolons to separate paths
rather than colons so that would need to be taken into account when
running on Windows. This also doesn't recognize shell built-ins, only
real binaries.

FWIW, "which" doesn't recognise built-ins either; the "type" built-in
does.
import os

def which(file):
for path in os.environ["PATH"].split(":"):
if file in os.listdir(path):
print "%s/%s" % (path, file)

There are a couple of problems with this:

1. "which" only considers executable files, and the default behaviour is
to only display the first matching file. Also, I'm assuming that the OP
wants a function which returns the path rather than printing it.

2. os.listdir() requires read permission (enumerate permission) on each
directory. The standard "which" utility stat()s each possible candidate,
so it only requires execute permission (lookup permission) on the
directories. A secondary issue is performance; enumerating a directory to
check for a specific entry can be much slower than stat()ing the specific
entry. IOW:

def which(file):
for path in os.environ["PATH"].split(os.pathsep):
if os.access(os.path.join(path, file), os.X_OK):
return "%s/%s" % (path, file)

But for Windows, you also need to use PATHEXT, e.g.:

for dir in os.environ["PATH"].split(os.pathsep):
for ext in os.environ["PATHEXT"].split(os.pathsep):
full = os.path.join(dir, "%s.%s" % (file, ext))
if os.access(full, os.X_OK):
return full

Disclaimer: I don't know how accurate os.access(..., os.X_OK) is on
Windows; OTOH, it's probably as good as you'll get.
 
R

Robert Kern

I realize four lines of Python does not replicate the functionality of
which exactly. It was intended to give the original poster something
to start with.

I am curious about it being slow, though. Is there a faster way to get
the contents of a directory than os.listdir() or is there a faster way
to see if an element is in a list other than "x in y"? I believe
'which' will terminate once it finds any match, which mine does not,
but that can be fixed by adding a break after the print.

Just check if os.path.exists(os.path.join(path, filename)).

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
N

Nobody

I realize four lines of Python does not replicate the functionality of
which exactly. It was intended to give the original poster something
to start with.

I am curious about it being slow, though. Is there a faster way to get
the contents of a directory than os.listdir()
No.

or is there a faster way to see if an element is in a list other than
"x in y"?

No.

However, there is a faster (and more correct) way to test for file
existence than enumerating the directory then checking whether the file is
in the resulting list, namely to stat() the file. I.e. os.path.exists()
or os.access(); the latter will allow you to check for execute permission
at the same time.

On some systems, the speed difference may be very significant. If
readdir() is a system call, os.listdir() will make one system call (two
context switches) per directory entry, while os.access() will make one
system call in total.

[Linux has the (non-standard) getdents() system call, which returns
multiple directory entries per call. The readdir() library
function uses getdents(), as it is much more efficient than using the
readdir() system call.]
 
N

Nobody

You don't need to get the entire directory content to see if a file
exists. The stat() syscall is much faster because it requires fewer disk
reads. On modern file systems stat() is a O(1) operation while "file" in
listdir() is a O(n) operation.

Apart from performance, stat() is more correct. readdir() (and Linux'
getdents()) requires read permission on the directory, while stat() (and
open() etc) only requires execute permission.

On shared web (etc) servers, it's not uncommon for system directories
(e.g. /usr/bin) to be "drwxr-x--x", as normal users shouldn't need to
enumerate these directories.
 
T

Trent Mick

destroooooy said:
Hi,
I'm looking for a Python library function that provides the same
functionality as the `which' command--namely, search the $PATH
variable for a given string and see if it exists anywhere within. I
currently examine the output from `which' itself, but I would like
something more portable. I looked through the `os' and `os.path'
modules but I didn't find anything.

http://code.google.com/p/which/


Trent
 
M

MRAB

Tim said:
I realize four lines of Python does not replicate the functionality of
which exactly. It was intended to give the original poster something
to start with.

I am curious about it being slow, though. Is there a faster way to get
the contents of a directory than os.listdir() or is there a faster way
to see if an element is in a list other than "x in y"? I believe
'which' will terminate once it finds any match, which mine does not,
but that can be fixed by adding a break after the print.

Have a look at os.path.isfile(), os.path.isdir() and os.path.islink().
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,128
Latest member
ElwoodPhil
Top