以冲突的可执行文件/路径打开
问题描述
我想使用 Popen 从我的 Python 脚本中调用 ImageMagick 的转换"实用程序,如下所示:
I'd like to call the "convert" utility from ImageMagick from my Python script using Popen, like so:
Popen(["convert", input_path, "-flop", output_file_path])
(上面的例子只是将图像水平反转)
(The above example simply reverses the image horizontally)
问题是当我在 Windows 中运行脚本时,它错误地调用了 Windows 附带的 convert.exe
实用程序将 FAT 分区转换为 NTFS!(位于Windowssystem32)
The problem is that when I run the script in Windows, it mistakenly calls the convert.exe
utility that ships with Windows to convert FAT partitions to NTFS! (located in Windowssystem32)
现在,如果我在 system32 以外的任何目录中随机打开命令提示符并键入convert",它会正确运行 ImageMagick 可执行文件.因此,这意味着 Popen 会自动在 system32 中查找.如何让它不在 system32 中查找,并运行正确的可执行文件?
Now, if I randomly open a command prompt at any directory other than system32, and type "convert", it correctly runs the ImageMagick executable. So, this implies that Popen is automatically looking in system32. How can I make it not look in system32, and run the correct executable?
解决方案
搜索一个程序并非易事.我会明确指定 convert.exe 可执行文件的完整路径.
Search for a program is not trivial. I'd specify the full path to the convert.exe executable explicitly instead.
subprocess
使用 CreateProcess 在
system32
目录中查找,甚至在 %PATH%
中的任何其他目录之前:
subprocess
uses CreateProcess
on Windows that looks in system32
directory even before any other directory in %PATH%
:
...如果文件名不包含扩展名,则附加.exe
.因此,如果文件扩展名为.com,则该参数必须包括 .com 扩展名.如果文件名以句点 (.) 结尾没有扩展名,或者如果文件名包含路径,则 .exe 不是附加.如果文件名不包含目录路径,则系统按以下顺序搜索可执行文件:
... If the file name does not contain an extension,
.exe
is appended. Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:
- 加载应用程序的目录.
- 父进程的当前目录.
- 32 位 Windows 系统目录.使用 GetSystemDirectory 函数获取该目录的路径.
- 16 位 Windows 系统目录.没有函数获取这个目录的路径,但是被搜索了.此目录的名称是 System.
- Windows 目录.使用 GetWindowsDirectory 函数获取该目录的路径.
- PATH 环境变量中列出的目录.请注意,此函数不会搜索 App Paths 注册表项指定的每个应用程序路径.要在搜索序列中包含此每个应用程序路径,请使用 ShellExecute 函数.
因此 convert
在这种情况下等同于 convert.exe
.它首先查找包含 sys.executable
的目录,例如 C:Python27
.然后在当前目录中:您启动 Python 脚本的位置.然后在 system32
中找到 convert.exe
(文件系统实用程序,而不是 imagemagick).
Therefore convert
is equivalent to convert.exe
in this case. It first looks in a directory that contains sys.executable
e.g., C:Python27
. Then in the current directory: where you started the Python script from. Then in system32
where it finds convert.exe
(filesystem utility, not imagemagick).
您可以尝试从 os.environ['PATH']
中删除 system32 目录,它可能(?)禁止检查它:Popen(cmd, env=no_system32_environ)
但它很脆弱(比显式路径更糟糕).
You could try to remove system32 directory from os.environ['PATH']
it may(?) suppress checking it: Popen(cmd, env=no_system32_environ)
but it is fragile (worse than the explicit path).
在 Python 错误跟踪器上有一个相关问题:"子进程在 Windows 上选择了错误的可执行文件."
There is a related issue on Python bug tracker: "Subprocess picks the wrong executable on Windows."
cmd.exe
(shell)使用不同的算法.请参阅Windows 如何定位在 shell 中输入的文件?
cmd.exe
(the shell) uses different algorithm. See How does Windows locate files input in the shell?
如果你设置 shell=True
那么 convert
程序的搜索顺序:
If you set shell=True
then the search sequence for convert
program:
convert
不是内部 shell 命令- 没有明确的路径,所以继续搜索
- 搜索当前目录
- 按列出的顺序搜索 PATH 环境变量指定的每个目录
convert
is not an internal shell command- there is no explicit path, so the search continues
- search the current directory
- search each directory specified by the PATH environment variable, in the order listed
%PATHEXT%
定义检查哪些文件扩展名以及检查顺序,例如 convert.com、convert.exe、convert.bat、convert.cmd if %PATHEXT%
是 .com;.exe;.bat;.cmd
.
%PATHEXT%
defines which file extensions are checked and in what order e.g., convert.com, convert.exe, convert.bat, convert.cmd if %PATHEXT%
is .com;.exe;.bat;.cmd
.
相关文章