Welcome, guest | Sign In | My Account | Store | Cart

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.)

This recipe shows how to write a minimal which command in Python. It has been tested on Windows.

Python, 40 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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()

This utility is written in Python 2.7.8 and tested on Windows 7, so far, though it should also work on most other platforms where Python runs, particularly UNIX, Linux and Mac OS X, since it uses no platform-specific Python code or libraries, and in fact, it explicitly uses features of the os.path module for portability, such as os.path.sep, os.path.pathsep, and os.path.exists.

More information, and example runs and outputs of the program, are available at this blog post:

http://jugad2.blogspot.in/2015/03/a-simple-unix-like-which-command-in.html

3 comments

Hongxu Chen 6 years, 8 months ago  # | flag

Actually this is which -a.

Vasudev Ram (author) 6 years, 8 months ago  # | flag

You're right, thanks for pointing it out. I had not thought of that at the time of writing the program. somehow.

-a or --all prints all programs that match (with their paths), not just the first.

I'll have to make a comment in my blog post about this too.

However, UNIX being what it is, even without my changing the code to support both the -a option and no -a option (correctly), people can easily work around the issue with this (on UNIX or a Windows that has a sed):

which foo | sed 1q

which will print only the first line of output, and when they want all lines, they can just do:

which foo

Hooray for UNIX! :)

Vasudev Ram (author) 6 years, 8 months ago  # | flag

I wrote another post with a corrected version of which.py, which now works for both the single and the -a / --all case:

http://jugad2.blogspot.in/2015/03/which-which-is-which.html