Я пишу grepath
утилиту, которая находит исполняемые файлы в %PATH%
, которые соответствуют шаблону.
Мне нужно определить, является ли данное имя файла в пути исполняемым (акцент делается на сценарии командной строки).
На основании «Скажите, является ли файл исполняемым» У меня есть:
import os
from pywintypes import error
from win32api import FindExecutable, GetLongPathName
def is_executable_win(path):
try:
_, executable = FindExecutable(path)
ext = lambda p: os.path.splitext(p)[1].lower()
if (ext(path) == ext(executable) # reject *.cmd~, *.bat~ cases
and samefile(GetLongPathName(executable), path)):
return True
# path is a document with assoc. check whether it has extension
# from %PATHEXT%
pathexts = os.environ.get('PATHEXT', '').split(os.pathsep)
return any(ext(path) == e.lower() for e in pathexts)
except error:
return None # not an exe or a document with assoc.
Где samefile
:
try: samefile = os.path.samefile
except AttributeError:
def samefile(path1, path2):
rp = lambda p: os.path.realpath(os.path.normcase(p))
return rp(path1) == rp(path2)
Как is_executable_win
можно улучшить в данном контексте? Какие функции из Win32 API могут помочь?
приписка
- производительность не имеет значения
subst
диски и UNC, пути Unicode не рассматриваются
- C ++ ответ в порядке, если он использует функции, доступные в Windows XP
Примеры
notepad.exe
исполняемый (как правило)
which.py
является исполняемым, если он связан с некоторым исполняемым файлом (например, python.exe), и .PY
находится в %PATHEXT%
, т.е. 'C:\> which'
может начинаться:
some\path\python.exe another\path\in\PATH\which.py
somefile.doc
наиболее вероятно, является не исполняемым (когда он связан с Word, например)
another_file.txt
является не исполняемым (как правило)
ack.pl
является исполняемым, если он связан с некоторым исполняемым файлом (наиболее вероятно, perl.exe), а .PL
находится в %PATHEXT%
(т.е. я могу запустить ack
без указания расширения, если оно находится в пути)
Что такое "исполняемый файл" в этом вопросе
def is_executable_win_destructive(path):
#NOTE: it assumes `path` <-> `barename` for the sake of example
barename = os.path.splitext(os.path.basename(path))[0]
p = Popen(barename, stdout=PIPE, stderr=PIPE, shell=True)
stdout, stderr = p.communicate()
return p.poll() != 1 or stdout != '' or stderr != error_message(barename)
Где error_message()
зависит от языка. Английская версия:
def error_message(barename):
return "'%(barename)s' is not recognized as an internal" \
" or external\r\ncommand, operable program or batch file.\r\n" \
% dict(barename=barename)
Если is_executable_win_destructive()
возвращается, когда он определяет, указывает ли путь на исполняемый файл для целей этого вопроса.
* +1073 * Пример: * 1 074 *
>>> path = r"c:\docs\somefile.doc"
>>> barename = "somefile"
После этого выполняется% COMSPEC% (cmd.exe по умолчанию):
c:\cwd> cmd.exe /c somefile
Если вывод выглядит так:
'somefile' is not recognized as an internal or external
command, operable program or batch file.
Тогда path
не является исполняемым файлом, иначе это (давайте предположим, что между path
и barename
для примера есть взаимно-однозначное соответствие).
Другой пример:
>>> path = r'c:\bin\grepath.py'
>>> barename = 'grepath'
Если .PY
в %PATHEXT%
и c:\bin
в %PATH%
, тогда:
c:\docs> grepath
Usage:
grepath.py [options] PATTERN
grepath.py [options] -e PATTERN
grepath.py: error: incorrect number of arguments
Вышеуказанный вывод не равен error_message(barename)
, поэтому 'c:\bin\grepath.py'
является "исполняемым".
Итак, вопрос в том, как выяснить, будет ли path
выдавать ошибку, не запуская ее? Какая функция Win32 API и какие условия использовались для вызова «не распознается как внутренняя ошибка ..»?