Проверить, существует ли исполняемый файл в Python?
в Python есть ли портативный и простой способ проверить, существует ли исполняемая программа?
под простым я подразумеваю что-то вроде which
команда, которая была бы просто идеально. Я не хочу искать путь вручную или что-то связанное с попыткой выполнить его с помощью Popen
& al и посмотреть, если это не удается (это то, что я делаю сейчас, но представьте, что это launchmissiles
)
22 ответа:
самый простой способ, который я могу придумать:
def which(program): import os def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file return None
Edit: обновленный пример кода для включения логики для обработки случая, когда предоставленный аргумент уже является полным путем к исполняемому файлу, т. е. "which /bin/ls". Это имитирует поведение команды UNIX 'which'.
Edit: обновлено для использования ОС.путь.isfile() вместо ОС.путь.существует() в комментариях.
Edit:
path.strip('"')
Кажется, что это неправильно. Ни Windows и POSIX, похоже, поощряют элементы пути в кавычках.
Я знаю, что это древний вопрос, но вы можете использовать
distutils.spawn.find_executable
. Это было документировано с python 2.4 и существует с python 1.6.import distutils.spawn distutils.spawn.find_executable("notepad.exe")
кроме того, Python 3.3 теперь предлагает
shutil.which()
.
в Python 3.3 теперь предлагает shutil.который ().
для python 3.2 и более ранних версий:
my_command = 'ls' any(os.access(os.path.join(path, my_command), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))
это один-лайнер Джей!--10-->, также здесь, как лямбда-функции:
cmd_exists = lambda x: any(os.access(os.path.join(path, x), os.X_OK) for path in os.environ["PATH"].split(os.pathsep)) cmd_exists('ls')
или, наконец, отступ как функция:
def cmd_exists(cmd): return any( os.access(os.path.join(path, cmd), os.X_OK) for path in os.environ["PATH"].split(os.pathsep) )
для python 3.3 и более поздних версий:
import shutil command = 'ls' shutil.which(command) is not None
как один-лайнер Ян-Филипп Герке Ответ:
cmd_exists = lambda x: shutil.which(x) is not None
как def:
def cmd_exists(cmd): return shutil.which(cmd) is not None
просто не забудьте указать расширение файла в windows. В противном случае, вы должны написать гораздо сложнее
is_exe
для windows с помощьюPATHEXT
переменные среды. Вы можете просто использовать FindPath.OTOH, почему вы даже беспокоитесь о поиске исполняемого файла? Операционная система сделает это за вас в рамках
popen
звонок и вызывает исключение, если исполняемый файл не найден. Все, что вам нужно сделать, это поймать правильное исключение для данной ОС. Отмечать что на окнах,subprocess.Popen(exe, shell=True)
просто не будет, еслиexe
не нашел.
включение
PATHEXT
в реализацииwhich
(в ответ Джея):def which(program): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) and os.path.isfile(fpath) def ext_candidates(fpath): yield fpath for ext in os.environ.get("PATHEXT", "").split(os.pathsep): yield fpath + ext fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) for candidate in ext_candidates(exe_file): if is_exe(candidate): return candidate return None
для платформ * nix (Linux и OS X)
это, кажется, работает для меня:
редактировать для работы на Linux, благодаря Mestreion
def cmd_exists(cmd): return subprocess.call("type " + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0
то, что мы делаем здесь, это использование встроенной команды
type
и проверка кода выхода. Если такой команды нет,type
выйдет с 1 (или ненулевым кодом состояния в любом случае).бит о stdout и stderr-это просто заставить замолчать вывод
type
команду, так как нас интересует только код состояния выхода.пример использования:
>>> cmd_exists("jsmin") True >>> cmd_exists("cssmin") False >>> cmd_exists("ls") True >>> cmd_exists("dir") False >>> cmd_exists("node") True >>> cmd_exists("steam") False
посмотреть ОС.путь модуль для некоторых полезных функций на пути. Чтобы проверить, является ли существующий файл исполняемым, используйте оС.доступ(путь, способ), С ОС.Режим прав.
ОС.Прав
значение, которое нужно включить в параметр режима access (), чтобы определить, можно ли выполнить path.
EDIT: предложил
which()
реализации не хватает одного ключа-с помощьюos.path.join()
построить полное имя файла.
на том основании, что он является легче просить прощения, чем разрешения Я бы просто попытался использовать его и поймать ошибку (OSError в этом случае - я проверил, что файл не существует, и файл не является исполняемым, и они оба дают OSError).
Это помогает, если исполняемый файл имеет что-то вроде
--version
флаг, который является быстрым no-op.import subprocess myexec = "python2.8" try: subprocess.call([myexec, '--version'] except OSError: print "%s not found on path" % myexec
это не общее решение, но будет самый простой способ для многих случаев - те, где код должен ищите один хорошо известный исполняемый файл.
я знаю, что я здесь немного некромант, но я наткнулся на этот вопрос, и принятое решение не сработало для меня для всех случаев, которые могли бы быть полезны для представления в любом случае. В частности, обнаружение "исполняемого" режима и требование предоставления расширения файла. Кроме того, оба python3.3-х
shutil.which
(используетPATHEXT
) и python2. 4+ ' sdistutils.spawn.find_executable
(просто старается добавлять'.exe'
) работает только в подмножестве случаев.поэтому я написал "супер" версию (на основе принятого ответа, и
PATHEXT
предложение от Сураж). Эта версияwhich
делает задачу немного более тщательно, и пробует серию" широкофазных " методов широты сначала, и в конечном итоге пробует более мелкозернистые поиски надPATH
площадь:import os import sys import stat import tempfile def is_case_sensitive_filesystem(): tmphandle, tmppath = tempfile.mkstemp() is_insensitive = os.path.exists(tmppath.upper()) os.close(tmphandle) os.remove(tmppath) return not is_insensitive _IS_CASE_SENSITIVE_FILESYSTEM = is_case_sensitive_filesystem() def which(program, case_sensitive=_IS_CASE_SENSITIVE_FILESYSTEM): """ Simulates unix `which` command. Returns absolute path if program found """ def is_exe(fpath): """ Return true if fpath is a file we have access to that is executable """ accessmode = os.F_OK | os.X_OK if os.path.exists(fpath) and os.access(fpath, accessmode) and not os.path.isdir(fpath): filemode = os.stat(fpath).st_mode ret = bool(filemode & stat.S_IXUSR or filemode & stat.S_IXGRP or filemode & stat.S_IXOTH) return ret def list_file_exts(directory, search_filename=None, ignore_case=True): """ Return list of (filename, extension) tuples which match the search_filename""" if ignore_case: search_filename = search_filename.lower() for root, dirs, files in os.walk(path): for f in files: filename, extension = os.path.splitext(f) if ignore_case: filename = filename.lower() if not search_filename or filename == search_filename: yield (filename, extension) break fpath, fname = os.path.split(program) # is a path: try direct program path if fpath: if is_exe(program): return program elif "win" in sys.platform: # isnt a path: try fname in current directory on windows if is_exe(fname): return program paths = [path.strip('"') for path in os.environ.get("PATH", "").split(os.pathsep)] exe_exts = [ext for ext in os.environ.get("PATHEXT", "").split(os.pathsep)] if not case_sensitive: exe_exts = map(str.lower, exe_exts) # try append program path per directory for path in paths: exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file # try with known executable extensions per program path per directory for path in paths: filepath = os.path.join(path, program) for extension in exe_exts: exe_file = filepath+extension if is_exe(exe_file): return exe_file # try search program name with "soft" extension search if len(os.path.splitext(fname)[1]) == 0: for path in paths: file_exts = list_file_exts(path, fname, not case_sensitive) for file_ext in file_exts: filename = "".join(file_ext) exe_file = os.path.join(path, filename) if is_exe(exe_file): return exe_file return None
использование выглядит так:
>>> which.which("meld") 'C:\Program Files (x86)\Meld\meld\meld.exe'
принятое решение не сработало для меня в этом случае, так как были файлы, такие как
meld.1
,meld.ico
,meld.doap
и т. д. Также в каталог, один из которых был возвращен вместо этого (предположительно, с лексикографически первого), потому что исполняемый тест в принятом ответе был неполным и давал ложные срабатывания.
лучшим примером должен быть python bulit-в модуле shutil.где() в Python 3. Ссылка https://hg.python.org/cpython/file/default/Lib/shutil.py
Я нашел что-то в StackOverflow, что решило проблему для меня. Это работает при условии, что исполняемый файл имеет опцию (например, --help или --version), которая выводит что-то и возвращает статус выхода ноль. Смотрите подавление вывода в Python вызовов исполняемых файлов - "результат" в конце фрагмента кода в этом ответе будет ноль, если исполняемый файл находится в пути, то это, скорее всего, будет 1.
это кажется достаточно простым и работает как в python 2 и 3
try: subprocess.check_output('which executable',shell=True) except: sys.exit('ERROR: executable not found')
если у вас
bash
иsh
(subprocess.Popen( ... ).communicate()
),
используйтеbash
builtintype
:type -p ls => /bin/ls type -p nonesuch => ""
важный вопрос-это "почему вам нужно проверить, существует ли исполняемый файл?- А может, и нет? ; -)
недавно мне понадобилась эта функция для запуска viewer для файла PNG. Я хотел перебрать некоторые предопределенные зрители и запустить первый, который существует. К счастью, я наткнулся
os.startfile
. Так гораздо лучше! Простой, портативный и использует по умолчанию просмотрщик в системе:>>> os.startfile('yourfile.png')
обновление: Я ошибся насчет
os.startfile
быть портативным... Это только окна. На Mac, вы должны выполнить . Иxdg_open
на Unix. Там есть проблема в Python при добавлении поддержки Mac и Unix дляos.startfile
.
вы можете попробовать внешний lib называется " sh " (http://amoffat.github.io/sh/).
import sh print sh.which('ls') # prints '/bin/ls' depending on your setup print sh.which('xxx') # prints None
добавлена поддержка windows
def which(program): path_ext = [""]; ext_list = None if sys.platform == "win32": ext_list = [ext.lower() for ext in os.environ["PATHEXT"].split(";")] def is_exe(fpath): exe = os.path.isfile(fpath) and os.access(fpath, os.X_OK) # search for executable under windows if not exe: if ext_list: for ext in ext_list: exe_path = "%s%s" % (fpath,ext) if os.path.isfile(exe_path) and os.access(exe_path, os.X_OK): path_ext[0] = ext return True return False return exe fpath, fname = os.path.split(program) if fpath: if is_exe(program): return "%s%s" % (program, path_ext[0]) else: for path in os.environ["PATH"].split(os.pathsep): path = path.strip('"') exe_file = os.path.join(path, program) if is_exe(exe_file): return "%s%s" % (exe_file, path_ext[0]) return None
вы можете сказать, если файл существует с модулем ОС. исполняемый файл, в частности, кажется совершенно не переносимым, учитывая, что многие вещи исполняются на nix, которые не находятся в windows, и наоборот.
казалось бы очевидно выбор-это "что", анализ результатов через popen, но вы можете имитировать его иначе, используя класс os. В псевдопитоне это будет выглядеть так:
for each element r in path: for each file f in directory p: if f is executable: return True
поэтому в основном вы хотите найти файл в смонтированной файловой системе (не обязательно только в каталогах пути) и проверить, является ли он исполняемым. Это приводит к следующему плану:
- перечислить все файлы в локально смонтированных файловых системах
- результаты матча с именем pattern
- для каждого найденного файла проверьте, является ли он исполняемым
Я бы сказал, что для этого портативного способа потребуется много вычислительной мощности и времени. Это действительно то, что вы нужно?
есть which.py скрипт в стандартном дистрибутиве Python (например, на Windows
'\PythonXX\Tools\Scripts\which.py'
).EDIT:
which.py
зависит отls
поэтому это не кросс-платформенный.
ни один из предыдущих примеров не работает на всех платформах. Обычно они не работают на Windows, потому что вы можете выполнить без расширения файла и что вы можете зарегистрировать новое расширения. Например, в Windows, если python хорошо установлен, достаточно выполнить 'file.py-и это сработает.
единственным допустимым и переносимым решением, которое у меня было, было выполнить команду и увидеть код ошибки. Любой приличный исполняемый файл должен иметь набор вызывающих параметров, которые будут делать ничего.