Popen с конфликтующим исполняемым файлом/path

Я хотел бы вызвать утилиту "convert" из ImageMagick из моего Python script с помощью Popen, например:

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

(Приведенный выше пример просто меняет изображение по горизонтали)

Проблема в том, что когда я запускаю script в Windows, он ошибочно вызывает утилиту convert.exe, которая поставляется с Windows для преобразования разделов FAT в NTFS! (находится в \Windows\system32)

Теперь, если я случайно открываю командную строку в любом каталоге, отличном от system32, и нажимаю "convert", он корректно запускает исполняемый файл ImageMagick. Таким образом, это означает, что Popen автоматически смотрит в system32. Как я могу заставить его не смотреть в system32 и запускать правильный исполняемый файл?

Ответ 1

Поиск программы не является тривиальным. Я бы явно указал полный путь к исполняемому файлу convert.exe.

subprocess использует CreateProcess в Windows, который выглядит в каталоге system32 даже перед любым другим каталогом в %PATH%:

... Если имя файла не содержит расширение, добавляется .exe. Поэтому, если расширение имени файла является .com, этот параметр должен включить расширение .com. Если имя файла заканчивается на период (.) С без расширения, или если имя файла содержит путь,.exe не является прилагается. Если имя файла не содержит пути к каталогу, система выполняет поиск исполняемого файла в следующей последовательности:

  • Каталог, из которого загружено приложение.
  • Текущий каталог для родительского процесса.
  • 32-разрядный системный каталог ОС Windows. Используйте функцию GetSystemDirectory, чтобы получить путь к этому каталогу.
  • 16-битный системный каталог ОС Windows. Нет функции, которая получает путь к этому каталогу, но выполняется поиск. Имя этого каталога - System.
  • Каталог Windows. Используйте функцию GetWindowsDirectory, чтобы получить путь к этому каталогу.
  • Каталоги, перечисленные в переменной среды PATH. Обратите внимание, что эта функция не ищет путь к каждому приложению, указанный в разделе реестра приложений. Чтобы включить этот путь для каждого приложения в последовательности поиска, используйте функцию ShellExecute.

Поэтому convert в этом случае эквивалентен convert.exe. Сначала он выглядит в каталоге, который содержит sys.executable например, C:\Python27. Затем в текущем каталоге: где вы запустили Python script из. Затем в system32, где он находит convert.exe (утилита файловой системы, а не imagemagick).

Вы можете попытаться удалить каталог system32 из os.environ['PATH'], он может (?) подавить его проверку: Popen(cmd, env=no_system32_environ), но он хрупкий (хуже, чем явный путь).

В Python есть ошибка: Подпроцесс выбирает неправильный исполняемый файл в Windows.


cmd.exe (оболочка) использует другой алгоритм. См. Как Windows находит файлы, вложенные в оболочку?

Если вы установите shell=True, то последовательность поиска для программы convert:

  • convert не является внутренней командой оболочки
  • нет явного пути, поэтому поиск продолжается
  • искать текущий каталог
  • найдите каждый каталог, указанный переменной среды PATH, в указанном порядке

%PATHEXT% определяет, какие расширения файлов проверяются и в каком порядке, например, convert.com, convert.exe, convert.bat, convert.cmd, если %PATHEXT% есть .com;.exe;.bat;.cmd.

Ответ 2

Как совершенно другой подход, вы можете попробовать PythonMagick, оболочку Python для ImageMagick. Таким образом, вы можете получить доступ к функциям convert из Python, и вам не придется запускать внешние процессы.

Ответ 3

Просто наткнулся на это сам. Запуск php script в оболочке имеет доступ к оболочке $PATH, в то время как в Apache нет (по крайней мере, не $PATH с Cygwin dll/exe).

Во-вторых, используйте собственную нотацию Windows C:/dir/subdir/pgm в php, когда на платформе Windows вы получите то, что ожидаете.

Таким образом, многоплатформенный код должен переключать/обрабатывать путь, а затем ссылаться на решение.