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) 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
$ which vim.exe
$ set PATH | grep -i vim73
$ addpath c:\vim\vim73
$ which.py vim.exe
$ which metapad.exe
$ which pscp.exe
$ which dostounix.exe
$ which pythonw.exe
# Which which is which? All four combinations:
$ which which
$ which.py which
$ which 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:
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:
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.
- Vasudev Ram - Online Python training and programming Dancing Bison EnterprisesSignup to hear about new products that I create. Posts about Python Posts about xtopdf Contact Page