如何在不指定文件扩展名的情况下运行Python脚本(跨平台解决方案)?

9 投票
6 回答
12653 浏览
提问于 2025-04-15 19:48

假设我们有一个Python脚本叫做 do.py,我们希望能够直接用 do 或者 ./do 来调用它,而不需要加上文件扩展名。

如果我们把文件名从 do.py 改成 do,并确保有一个有效的shebang行(就是文件开头的一行代码,用来指明用哪个程序来运行这个脚本),这样在大多数平台上都能正常工作,但在Windows上就不行。在Windows上,文件名后面没有扩展名是无法执行的。

在Windows上,如果我们保留原来的文件扩展名,就可以不写完整的文件名来调用这个脚本,因为Python的安装程序会把 .py 扩展名注册为可执行文件。

看起来我们需要用两个不同的名字来提供同一个脚本,以便在Windows和非Windows环境中都能调用。我其实不太喜欢这样重复的做法,所以我在寻找一个不需要这种冗余的解决方案。

另一种常见的做法是添加一个 do.cmd 的批处理文件,这个文件会调用原来的 do.py 文件。不过,这种方法有一个主要问题:它会破坏 Ctrl+C / Ctrl+Break 的功能,因为没有办法阻止 cmd.exe 弹出 是否终止批处理作业? (Y/N) 的提示。

如果我们决定使用一个包装器(wrapper),我们需要确保:

  • 返回原始脚本的错误代码(errorlevel)
  • 不会改变环境
  • 会重用同一个控制台(不打开新窗口)
  • 不干扰标准输出(STDOUT)、标准输入(STDIN)或标准错误(STDERR)
  • 对 Ctrl-C 友好(没有提示)

我认为最优的解决方案还是使用一个包装器。批处理文件不行,原生可执行文件会增加很多复杂性,所以可能用Python自己写一个包装器会比较合适。

6 个回答

5

首先,写一个主的Python模块,文件名要以.py结尾。然后,正确设置PATHEXT,这样在Windows上运行时就不用输入文件扩展名了。

在Unix系统上,你需要写一个第二个Python程序,这个程序只需要导入第一个程序,并且要使用she-bang语法。这个文件不需要扩展名,它是一个shell脚本。像这样:

#!/usr/bin/env python
import do

这样做的效果就是导入do.py这个文件。

在Unix上,只需要把do标记为可执行文件即可。do.py在这个环境中是一个模块。

当你导入一个模块时,模块里的代码会运行一次。

虽然这样做不能完全消除冗余,但已经很接近了。而且这可能是跨平台脚本的最佳解决方案。

5

在Windows系统上,我把'.py'这个扩展名加到了'PATHEXT'环境变量里,这样就能正常工作了——前提是这个.py文件存放在一个包含在'PATH'环境变量里的文件夹里。

C:\>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.PY;.JS;.JSE
2

到目前为止,我想出了一个看起来有效的解决方案。创建一个文件,命名为 yourname.py,并在里面写入以下内容:

import os, sys
filename = os.path.splitext(os.path.basename(sys.argv[0]))[0]
if not os.path.exists(filename):
    # filename does not exists, we will emulate cmd behaviour
    sys.stderr.write("'%s' is not recognized as an internal or external command,\noperable program or batch file." % filename)
    sys.exit(9009)
ret = os.system("python %s %s" % (
        filename,
        " ".join(sys.argv[1:])
        ))
exit(ret)

撰写回答