By
Vasudev Ram
UNIX users are familiar with the
which command. Given an argument called
name, it checks the system PATH environment variable, to see whether that name exists (as a file) in any of the directories specified in the PATH. (The directories in the PATH are colon-separated on UNIX and semicolon-separated on Windows.)
I'd written a Windows-specific version of the which command some time ago, in C.
Today I decided to write a simple version of the which command in Python. In the spirit of
YAGNI and incremental development, I tried to resist the temptation to add more features too early; but I did give in once and add the exit code stuff near the end :)
Here is the code for which.py:
from __future__ import print_function
# which.py
# A minimal version of the UNIX which utility, in Python.
# Author: Vasudev Ram - www.dancingbison.com
# Copyright 2015 Vasudev Ram - http://www.dancingbison.com
import sys
import os
import os.path
import stat
def usage():
sys.stderr.write("Usage: python which.py name\n")
sys.stderr.write("or: which.py name\n")
def which(name):
found = 0
for path in os.getenv("PATH").split(os.path.pathsep):
full_path = path + os.sep + name
if os.path.exists(full_path):
"""
if os.stat(full_path).st_mode & stat.S_IXUSR:
found = 1
print(full_path)
"""
found = 1
print(full_path)
# Return a UNIX-style exit code so it can be checked by calling scripts.
# Programming shortcut to toggle the value of found: 1 => 0, 0 => 1.
sys.exit(1 - found)
def main():
if len(sys.argv) != 2:
usage()
sys.exit(1)
which(sys.argv[1])
if "__main__" == __name__:
main()
And here are a few examples of using the command:
(Note: the tests are done on Windows, though the command prompt is a $ sign (UNIX default); I just set it to that because I like $'s and UNIX :)
$ which vim
\vim
$ which vim.exe
C:\Ch\bin\vim.exe
$ set PATH | grep -i vim73
$ addpath c:\vim\vim73
$ which.py vim.exe
C:\Ch\bin\vim.exe
c:\vim\vim73\vim.exe
$ which metapad.exe
C:\util\metapad.exe
$ which pscp.exe
C:\util\pscp.exe
C:\Ch\bin\pscp.exe
$ which dostounix.exe
C:\util\dostounix.exe
$ which pythonw.exe
C:\Python278\pythonw.exe
D:\Anaconda-2.1.0-64\pythonw.exe
# Which which is which? All four combinations:
$ which which
.\which
$ which.py which
.\which
$ which which.py
.\which.py
$ which.py which.py
.\which.py
As you can see, calling the
which Python command with different arguments, gives various results, including sometimes finding
one instance of
vim.exe and sometimes
two instances, depending on the values in the
PATH variable (which I changed, using my
addpath.bat script, to add the
\vim\vim73 directory to it).
Also, it works when invoked either as
which.py or just
which.
I'll discuss my interpretation of these variations in an upcoming post - including a variation that uses
os.stat(full_path).st_mode - see the commented part of the code under the line:
if os.path.exists(full_path):
Meanwhile, did you know that
YAGNI was written about much before
agile was a thing? IIRC, I've seen it described in either
Kernighan and Ritchie (
The C Programming Language) or in
Kernighan and Pike (
The UNIX Programming Environment). It could be possibly be older than that, say from the mainframe era.
Finally, as I was adding labels to this blog post, Blogger showed me "pywhich" as a label, after I typed "which" in the labels box. That reminded me that I had written another post earlier about a Python which utility (not by me), so I found it on my blog by typing in this URL:
http://jugad2.blogspot.in/search/label/pywhich
which finds all posts on my blog with the label 'pywhich' (and the same approach works for any other label); the resulting post is:
pywhich, like the Unix which tool, for Python modules.
- Enjoy.
- Vasudev Ram - Online Python training and programming
Dancing Bison Enterprises
Signup to hear about new products that I create.
Posts about Python Posts about xtopdf
Contact Page