Проверить, существует ли исполняемый файл в Python?
В Python существует ли переносимый и простой способ проверить, существует ли исполняемая программа?
Простым я имею в виду что-то вроде команды which
, которая была бы просто идеальной. Я не хочу искать PATH вручную или что-то, что пытается выполнить его с помощью Popen
и al и посмотреть, не сработает ли он (что я сейчас делаю, но представьте себе launchmissiles
)
Ответы
Ответ 1
Самый простой способ, о котором я могу думать:
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
Изменить. Обновленный образец кода, чтобы включить логику для обработки случая, когда предоставленный аргумент уже является полным путем к исполняемому файлу, то есть "который/bin/ls". Это имитирует поведение команды UNIX, которая ".".
Изменить: Обновлено для использования os.path.isfile() вместо os.path.exists() для комментариев.
Изменить: path.strip('"')
кажется неправильным. Ни Windows, ни POSIX, похоже, не поддерживают цитируемые элементы PATH.
Ответ 2
Я знаю, что это древний вопрос, но вы можете использовать distutils.spawn.find_executable
. Это было задокументировано с python 2.4 и существует с python 1.6.
import distutils.spawn
distutils.spawn.find_executable("notepad.exe")
Кроме того, Python 3.3 теперь предлагает shutil.which()
.
Ответ 3
Теперь Python 3.3 предлагает shutil.which().
Ответ 4
Для 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))
Это один лайнер Jay Answer, также здесь как функция лямбда:
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
Ответ 5
Не забудьте указать расширение файла на окнах. В противном случае вам придется написать сложный is_exe
для Windows, используя переменную среды PATHEXT
. Вы можете просто использовать FindPath.
OTOH, почему вы даже пытаетесь найти исполняемый файл? Операционная система сделает это для вас как часть вызова popen
и вызовет исключение, если исполняемый файл не будет найден. Все, что вам нужно сделать, это поймать правильное исключение для данной ОС. Обратите внимание, что в Windows, 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
Ответ 6
Для платформ * 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
Ответ 7
Смотрите модуль os.path для некоторых полезных функций в путевых именах. Чтобы проверить, является ли существующий файл исполняемым, используйте os.access (путь, режим) с режимом os.X_OK.
os.X_OK
Значение, которое необходимо включить в параметр режима доступа(), чтобы определить, может ли быть выполнен путь.
ОБНОВЛЕНИЕ: В предлагаемых реализациях which()
отсутствует одна подсказка - использование os.path.join()
для создания полных имен файлов.
Ответ 8
Исходя из того, что проще просить прощения, чем разрешения, я бы просто попытался использовать его и уловить ошибку (в данном случае OSError - я проверил, что файл не существует, а файл не исполняемый, и оба дать OSError).
Помогает, если у исполняемого файла есть что-то вроде флага --version
, который быстро не используется.
import subprocess
myexec = "python2.8"
try:
subprocess.call([myexec, '--version']
except OSError:
print "%s not found on path" % myexec
Это не общее решение, но оно будет самым простым способом для многих случаев использования - тех, где код должен искать один хорошо известный исполняемый файл.
Ответ 9
Я знаю, что здесь я немного некромант, но я наткнулся на этот вопрос, и принятое решение не работало для меня во всех случаях. Думал, что это может быть полезно подать в любом случае. В частности, обнаружение "исполняемого" режима и требование предоставления расширения файла. Кроме того, как python3.3 shutil.which
(использует PATHEXT
), так и python2.4 + distutils.spawn.find_executable
(просто пытается добавить '.exe'
) работает только в подмножестве случаев.
Итак, я написал "супер" версию (на основе принятого ответа и предложение PATHEXT
от Suraj). Эта версия 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
и т.д., и один из них был возвращен (предположительно, поскольку лексикографически первый) потому что исполняемый тест в принятом ответе был неполным и давал ложные срабатывания.
Ответ 10
Лучшим примером может быть модуль bulit-in для python shutil.which() в Python 3. Ссылка https://hg.python.org/cpython/file/default/Lib/shutil.py
Ответ 11
Я нашел что-то в StackOverflow, который решил проблему для меня. Это работает, если у исполняемого файла есть опция (например, --help или --version), которая выводит что-то и возвращает статус выхода из нуля. См. Подавить вывод в Python-вызовах для исполняемых файлов - "результат" в конце фрагмента кода в этом ответе будет равен нулю, если исполняемый файл находится в пути, иначе он будет скорее всего, будет 1.
Ответ 12
Это кажется достаточно простым и работает как в python 2, так и в 3
try: subprocess.check_output('which executable',shell=True)
except: sys.exit('ERROR: executable not found')
Ответ 13
Если у вас есть bash
и функция sh
(subprocess.Popen( ... ).communicate()
),
используйте bash
builtin type
:
type -p ls => /bin/ls
type -p nonesuch => ""
Ответ 14
Важным вопросом является " Почему вам нужно проверить, существует ли исполняемый файл?" Может, нет?;-)
Недавно мне понадобилась эта функция для запуска программы просмотра PNG файла. Я хотел перебрать некоторые предопределенные зрители и запустить первый, который существует. К счастью, я наткнулся на os.startfile
. Это намного лучше! Простой, портативный и использует средство просмотра по умолчанию в системе:
>>> os.startfile('yourfile.png')
Обновление: Я был неправ, когда os.startfile
был переносимым... Это только Windows. На Mac вам нужно запустить команду open
. И xdg_open
в Unix. Там проблема с Python при добавлении поддержки Mac и Unix для os.startfile
.
Ответ 15
Вы можете попробовать внешний 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
Ответ 16
Поддержка дополнительных окон
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
Ответ 17
вы можете узнать, существует ли файл с модулем os. исполняемый файл, в частности, кажется совершенно неспортивным, учитывая, что многие вещи исполняются на nix, которые не находятся на окнах, и наоборот.
Ответ 18
Казалось бы, очевидным выбором является "кто", анализируя результаты через popen, но вы могли бы имитировать его иначе, используя класс os. В псевдопитоне это будет выглядеть так:
for each element r in path:
for each file f in directory p:
if f is executable:
return True
Ответ 19
Итак, в основном вы хотите найти файл в смонтированной файловой системе (не обязательно в каталогах PATH) и проверить, является ли он исполняемым. Это соответствует следующему плану:
- перечислять все файлы в локально смонтированных файловых системах.
- Результаты сопоставления с шаблоном имени
- для каждого найденного файла проверяется, является ли он исполняемым.
Я бы сказал, что для этого в переносном режиме потребуется много вычислительной мощности и времени. Это действительно то, что вам нужно?
Ответ 20
В стандартном дистрибутиве Python (например, в Windows '\PythonXX\Tools\Scripts\which.py'
) есть which.py script.
EDIT: which.py
зависит от ls
, поэтому он не является кросс-платформенным.
Ответ 21
Ни один из предыдущих примеров не работает на всех платформах. Обычно они не работают в Windows, потому что вы можете выполнить без расширения файла и что вы можете зарегистрировать новое расширение. Например, в Windows, если python хорошо установлен, достаточно выполнить "file.py", и он будет работать.
Единственное допустимое и портативное решение, которое у меня было, это выполнить команду и увидеть код ошибки. Любой достойный исполняемый файл должен иметь набор параметров вызова, которые ничего не сделают.
Ответ 22
Использование библиотеки библиотеки python:
from fabric.api import *
def test_cli_exists():
"""
Make sure executable exists on the system path.
"""
with settings(warn_only=True):
which = local('which command', capture=True)
if not which:
print "command does not exist"
assert which