您的位置:首页 > 运维架构 > Linux

用Python在Windows下模仿Linux的|which.exe|程序

2012-04-01 00:00 369 查看
简介
用Python在Windows下模仿Linux的|which.exe|程序。

这个程序会从Windows环境变量|PATH|里列出的所有目录中查找"可执行文件"。

在Linux下|which.exe|通过文件的"可执行"属性来判断文件是否可执行不同。

在Windows下我们通过扩展名来判断。

如果一个文件的扩展名是|.exe|, |.bat|,或者任何在Windows环境变量|PATHEXT|中列出的扩展名(比如我们自己添加的|.py|),则认为这个文件为"可执行文件"。这个定义也符合Windows的CMD对"可执行文件"的定义。

源码
闲话少说,先上源码。实现的具体分析见源码中注释及源码后的分析。

__doc__ = """
Author: kuiyuyou@gmail.com
File: aoiwhich.py
"""

import sys
import os

def find_executable(program):
""" Given |program| which is the name or path of a program, find a list of
executable paths of the program.

#// Arguments
program: the name or path of a program. No need to include extension.
return: a list of executable paths of the program.

#// What an "executable" means?
An executable means an existing file whose extension is |.exe|, |.bat|, or
any other extensions listed in Windows environment variable |PATHEXT|.

#// What is the algorithm used to find all the executable paths?
Use each of dir paths listed in Windows environment variable |PATH| as parent dir.

Use each of extensions listed in Windows environment variable |PATHEXT| as extension.

Synthesize all the possible paths by combining each parent dir, the |program| given,
and each extension. (Empty parent dir and empty extension are two special cases.)

Check if each path synthesized is an existing executable path.
"""
#//
if not isinstance(program, str): raise TypeError(program)

#// create a list to store all the executable paths found
the_path_s = []

#// get environment variable |PATHEXT|'s value
the_PATHEXT = os.environ.get('PATHEXT')
## |os.environ.get| returns either a str or None

#// split |the_PATHEXT| into a list of extensions
if the_PATHEXT is None:
the_ext_s = []
else:
the_ext_s = the_PATHEXT.split(os.pathsep)
## |os.pathsep| on Windows is |;|

#// change each item in [the_ext_s] into lowercase
the_ext_s = [x.lower() for x in the_ext_s]

#// add '.exe' to |the_ext_s| if it is NOT in
if '.exe' not in the_ext_s:
the_ext_s.append('.exe')

#// add '.bat' to |the_ext_s| if it is NOT in
if '.bat' not in the_ext_s:
the_ext_s.append('.bat')

## The reason to add '.exe' and '.bat':
##
## On Windows, files with an extension of '.exe' or '.bat' are considered
## executable, even if '.exe' and '.bat' are not listed in environment
## variable |PATHEXT|.
##
## However, the algorithm below requires that, an "executable" msut have one
## of the extensions in |the_ext_s|. So to ensure that the algorithm can
## always recognize '.exe' and '.bat' files as executable, we add '.exe' and
## '.bat' to |the_ext_s| manually if they are not listed in |PATHEXT|.

#// get a tuple version of |the_ext_s|
## becasue |string.endswith| below takes tuple but not list as argument
the_ext_s_tuple = tuple(the_ext_s)

#// check if |program| given is an executable full path
if os.path.isfile(program) and program.endswith(the_ext_s_tuple):
the_path_s.append(program)
## do not return immediately here because if |program| is a relative path,
## algorithm below may find its absolute path as well, e.g.
## if |aoiwhich.py| file's parent dir has been added to PATH, then
## in the same dir, run command |aoiwhich.py aoiwhich.py| would find both
## the relative path |aoiwhich.py| as well as an absolute path.

#// get the environment variable |PATH|'s value
the_PATH = os.environ.get('PATH')
## |os.environ.get| returns either a str or None

#// split |the_PATH| into a list of dir paths
if the_PATH is None:
the_dir_path_s = []
else:
the_dir_path_s = the_PATH.split(os.pathsep)
## |os.pathsep| on Windows is |;|

#// insert empty dir path to the beginning of the list of dir paths
if '' not in the_dir_path_s:
the_dir_path_s.insert(0, '')

#// get unique dir paths
the_dir_path_s_unique = []
for the_dir_path in the_dir_path_s:
if the_dir_path not in the_dir_path_s_unique:
the_dir_path_s_unique.append(the_dir_path)

#// synthesize possible executable paths.
#// check whether each of the synthesized executable paths is existing executable path.
for the_dir_path in the_dir_path_s_unique:
# synthesize a path
# use |the_dir_path| as the parent dir
# use |program| as the file name (assuming it has included extension)
# use no extension
the_path_synthesized = os.path.join(the_dir_path, program)

# check if the path synthesized is an existing executable path
if os.path.isfile(the_path_synthesized) and the_path_synthesized.endswith(the_ext_s_tuple):
the_path_s.append(the_path_synthesized)

#
for the_ext in the_ext_s:
# synthesize a path
# use |the_dir_path| as the parent dir
# use |program| as the file name (assuming it has NOT included extension)
# use |the_ext| as the extension
the_path_synthesized_plus_ext = the_path_synthesized + the_ext

# check if the path synthesized is an existing executable path
if os.path.isfile(the_path_synthesized_plus_ext):
the_path_s.append(the_path_synthesized_plus_ext)

#// make the list items unique
the_path_s_unique = []
for the_path in the_path_s:
if the_path not in the_path_s_unique:
the_path_s_unique.append(the_path)

#//
return the_path_s_unique

if __name__ == '__main__':
#//
if len(sys.argv) != 2:
print('Usage: {} PROGRAM'.format(sys.argv[0]))
print('Example: {} {}'.format(sys.argv[0], 'notepad'))
sys.exit(0)
## I was using |argparse| module to parse the arguments, which was very
## convenient. However, |argparse| module is available only since python
## version 3.2. So here I simply check the number of arguments given instead.

#//
the_program = sys.argv[1]

#// find paths according to program name given
the_path_s = find_executable(the_program)

#// has found NO paths, exit
if len(the_path_s) == 0:
sys.exit(0)

#// has found some paths, print
print('\n'.join(the_path_s))


分析
通过|os.environ.get('PATHEXT')|和|os.environ.get('PATH')|分别得到Window环境变量|PATHEXT|和|PATH|的值。 ## 注意,当这些变量在注册表中没有定义时,|os.environ.get|返回的是None而不是空的list。

将这两个值用|split|拆分为多项。|PATHEXT|的每一个项是一个扩展名(包括点)。|PATH|的每一个项是一个目录路径。

通过将每一个目录路径,与函数参数|program|,与每一个扩展名相组合,得到所有可能的可执行文件的路径。 ## 有两个特殊情况应考虑在内,一个是目录为当前目录,一个是函数参数|program|已经包含了扩展名。

再用|os.path.isfile|判断该路径是否是一个存在的文件。

最后将找到的所有路径打印出来。

用法
先将存有源码的文件命名为|aoiwhich.py|。

在命令行运行:

python aoiwhich.py notepad

在俺的机器上得到:

C:\Windows\system32\notepad.exe
C:\Windows\notepad.exe

在命令行运行:

python aoiwhich.py regedit

在俺的机器上得到:

C:\Windows\system32\regedit.exe
C:\Windows\regedit.exe


此软件已开源到 http://sourceforge.net/p/aoiwhich/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息