Popen与冲突的可执行文件/路径

5 投票
3 回答
2374 浏览
提问于 2025-04-18 13:35

我想在我的Python脚本中使用Popen来调用ImageMagick的“convert”工具,像这样:

Popen(["convert", input_path, "-flop", output_file_path])

(上面的例子只是把图像水平翻转了一下)

问题是,当我在Windows上运行这个脚本时,它错误地调用了Windows自带的convert.exe工具,这个工具是用来把FAT分区转换成NTFS的!这个工具在\Windows\system32文件夹里。

现在,如果我在除了system32以外的任何目录下随机打开命令提示符,输入“convert”,它就能正确运行ImageMagick的可执行文件。所以,这说明Popen自动在system32文件夹里查找。请问我该怎么做才能让它不去system32查找,而是运行正确的可执行文件呢?

3 个回答

0

我刚遇到这个问题。通过命令行运行一个php脚本时,它可以访问到命令行的$PATH环境变量,但在Apache服务器中运行时就不能访问(至少不能访问到包含Cygwin的dll/exe的$PATH)。

其次,在Windows系统上使用php时,记得用Windows的路径格式,比如C:/dir/subdir/pgm,这样你就能得到预期的结果。

所以,如果你的代码要在不同的平台上运行,就需要根据不同的情况来处理路径,然后根据这个决定来引用路径。

2

作为一种完全不同的方法,你可以试试PythonMagick,这是一个用于ImageMagick的Python封装。这样你就可以在Python里面直接使用convert的功能,而不需要去启动其他的程序。

8

寻找一个程序并不是一件简单的事。我建议你直接指定convert.exe的完整路径

subprocess在Windows上使用CreateProcess,它会先在system32目录中查找文件,然后才会去%PATH%中的其他目录:

... 如果文件名没有扩展名,系统会自动加上.exe。因此,如果文件名的扩展名是.com,那么这个参数必须包含.com扩展名。如果文件名以一个句点(.)结尾且没有扩展名,或者文件名包含路径,则不会加上.exe。如果文件名没有目录路径,系统会按以下顺序查找可执行文件:

  1. 应用程序加载的目录。
  2. 父进程的当前目录。
  3. 32位Windows系统目录。可以使用GetSystemDirectory函数获取这个目录的路径。
  4. 16位Windows系统目录。没有函数可以获取这个目录的路径,但系统会进行查找。这个目录的名称是System。
  5. Windows目录。可以使用GetWindowsDirectory函数获取这个目录的路径。
  6. 在PATH环境变量中列出的目录。注意,这个函数不会查找由App Paths注册表键指定的每个应用程序路径。如果想在查找顺序中包含这个每个应用程序路径,可以使用ShellExecute函数。

因此,在这种情况下,convert等同于convert.exe。它首先会在包含sys.executable的目录中查找,比如C:\Python27。然后在你启动Python脚本的当前目录中查找。最后在system32中找到convert.exe(这是一个文件系统工具,而不是imagemagick)。

你可以尝试从os.environ['PATH']中移除system32目录,这可能会抑制对它的检查:Popen(cmd, env=no_system32_environ),但这样做不太可靠(比直接指定路径更糟糕)。

在Python的错误追踪器上有一个相关的问题:“子进程在Windows上选择了错误的可执行文件。”


cmd.exe(命令行)使用不同的算法。请参见Windows是如何定位在命令行中输入的文件的?

如果你设置了shell=True,那么convert程序的查找顺序是:

  1. convert不是内部命令
  2. 没有明确的路径,所以继续查找
  3. 查找当前目录
  4. 按顺序查找PATH环境变量中指定的每个目录

%PATHEXT%定义了检查哪些文件扩展名以及顺序,例如,如果%PATHEXT%.com;.exe;.bat;.cmd,那么会检查convert.com、convert.exe、convert.bat和convert.cmd。

撰写回答