Проверьте, существует ли программа из python script
Как проверить, существует ли программа из python script?
Предположим, вы хотите проверить, доступны ли wget
или curl
. Мы предположим, что они должны быть в пути.
Было бы лучше увидеть многоплатформенное решение, но на данный момент Linux достаточно.
Советы:
- выполнение команды и проверка кода возврата не всегда достаточно, так как некоторые инструменты возвращают результат не 0, даже если вы пытаетесь выполнить
--version
.
- ничто не должно отображаться на экране при проверке команды
Кроме того, я был бы признателен за решение, которое является более общим, например is_tool(name)
Ответы
Ответ 1
import subprocess
import os
def is_tool(name):
try:
devnull = open(os.devnull)
subprocess.Popen([name], stdout=devnull, stderr=devnull).communicate()
except OSError as e:
if e.errno == os.errno.ENOENT:
return False
return True
Ответ 2
shutil.which
Позвольте мне порекомендовать вариант, который еще не обсуждался: реализация Python which
, в частности shutil.which
. Он был представлен в Python 3.3 и является кросс-платформенным, поддерживающим Linux, Mac и Windows. Он также доступен в Python 2.x через whichcraft. Вы также можете просто скопировать код which
прямо из
Другой вариант, который уже упоминался, - distutils.spawn.find_executable
.
find_executable
docstring выглядит следующим образом:
Пытается найти "исполняемый файл" в каталогах, перечисленных в "пути"
Итак, если вы обратите внимание, вы заметите, что имя функции несколько вводит в заблуждение. В отличие от which
, find_executable
на самом деле не проверяет, что executable
помечен как исполняемый файл, только то, что он находится в PATH. Таким образом, вполне возможно (что маловероятно), что find_executable
указывает, что программа доступна, когда она отсутствует.
Например, предположим, что у вас есть файл /usr/bin/wget
, который не отмечен как исполняемый. Запуск wget
из оболочки приведет к следующей ошибке: bash:/usr/bin/wget: Permission denied. which('wget') is not None
вернет False, но find_executable('wget') is not None
вернет True. Вероятно, вам удастся использовать любую функцию, но об этом просто нужно знать с помощью find_executable
.
def is_tool(name):
"""Check whether `name` is on PATH."""
from distutils.spawn import find_executable
return find_executable(name) is not None
Ответ 3
Самый простой способ - попытаться запустить программу с нужными параметрами и обработать исключение, если оно не существует:
try:
subprocess.call(["wget", "your", "parameters", "here"])
except OSError as e:
if e.errno == errno.ENOENT:
# handle file not found error.
else:
# Something else went wrong while trying to run 'wget'
raise
Это обычный шаблон в Python: EAFP
Ответ 4
Вы можете использовать вызов подпроцесса в двоичный файл, необходимый с помощью:
- "which": * nix
- "where": Win 2003 и более поздние версии (Xp имеет аддон)
чтобы получить исполняемый путь (предположим, что он находится в пути к среде).
import os
import platform
import subprocess
cmd = "where" if platform.system() == "Windows" else "which"
try:
subprocess.call([cmd, your_executable_to_check_here])
except:
print "No executable"
или просто используйте Ned Batchelder wh.py script, то есть "какую" кроссплатформенную реализацию:
http://nedbatchelder.com/code/utilities/wh_py.html
Ответ 5
Я бы пошел за:
import distutils.spawn
def is_tool(name):
return distutils.spawn.find_executable(name) is not None
Ответ 6
Я бы, вероятно, выложил в which wget
или which curl
и проверил, что результат заканчивается именем программы, которую вы используете. Магия юникса :)
На самом деле все, что вам нужно сделать, это проверить код возврата which
. Итак... используя наш надежный модуль subprocess
:
import subprocess
rc = subprocess.call(['which', 'wget'])
if rc == 0:
print 'wget installed!'
else:
print 'wget missing in path!'
Обратите внимание, что я проверял это на Windows с Cygwin... Если вы хотите выяснить, как реализовать which
в чистом Python, я предлагаю вам проверить здесь: http://pypi.python.org/pypi/pycoreutils (о дорогой - кажется, они не снабжение which
. Время для дружеского толчка?)
ОБНОВЛЕНИЕ: В Windows вы можете использовать where
вместо which
для аналогичного эффекта.
Ответ 7
Я бы изменил ответ @sorin следующим образом, причина в том, что он будет проверять имя программы без прохождения абсолютного пути к программе
from subprocess import Popen, PIPE
def check_program_exists(name):
p = Popen(['/usr/bin/which', name], stdout=PIPE, stderr=PIPE)
p.communicate()
return p.returncode == 0
Ответ 8
import os
import subprocess
def is_tool(prog):
for dir in os.environ['PATH'].split(os.pathsep):
if os.path.exists(os.path.join(dir, prog)):
try:
subprocess.call([os.path.join(dir, prog)],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
except OSError, e:
return False
return True
return False
Ответ 9
Небольшая модификация кода @SvenMarnach, которая устраняет проблему печати в стандартный выходной поток. Если вы используете функцию subprocess.check_output()
, а не subprocess.call()
, тогда вы можете обрабатывать строку, которая обычно печатается стандартным образом в вашем коде, и все еще ловить исключения и код состояния выхода.
Если вы хотите подавить стандартный выходной поток в терминале, не печатайте строку std out, которая возвращается из check_output
:
import subprocess
import os
try:
stdout_string = subprocess.check_output(["wget", "--help"], stderr=subprocess.STDOUT)
# print(stdout_string)
except subprocess.CalledProcessError as cpe:
print(cpe.returncode)
print(cpe.output)
except OSError as e:
if e.errno == os.errno.ENOENT:
print(e)
else:
# Something else went wrong while trying to run `wget`
print(e)
Не нулевой код статуса выхода и строка вывода повышены в CalledProcessError
как subprocess.CalledProcessError.returncode
и subprocess.CalledProcessError.output
, чтобы вы могли делать с ними все, что захотите.
Если вы хотите распечатать исполняемый стандартный вывод на терминал, напечатайте возвращаемую строку:
import subprocess
import os
try:
stdout_string = subprocess.check_output(["wget", "--help"], stderr=subprocess.STDOUT)
print(stdout_string)
except subprocess.CalledProcessError as cpe:
print(cpe.returncode)
print(cpe.output)
except OSError as e:
if e.errno == os.errno.ENOENT:
print(e)
else:
# Something else went wrong while trying to run `wget`
print(e)
print()
добавляет дополнительную строку строки строки. Если вы хотите устранить это (и записать std-ошибку в std-поток err-потока вместо потока std out, как показано выше с помощью операторов print(), используйте sys.stdout.write(string)
и sys.stderr.write(string)
вместо print():
import subprocess
import os
import sys
try:
stdout_string = subprocess.check_output(["bogus"], stderr=subprocess.STDOUT)
sys.stdout.write(stdout_string)
except subprocess.CalledProcessError as cpe:
sys.stderr.write(cpe.returncode)
sys.stderr.write(cpe.output)
except OSError as e:
if e.errno == os.errno.ENOENT:
sys.stderr.write(e.strerror)
else:
# Something else went wrong while trying to run `wget`
sys.stderr.write(e.strerror)
Ответ 10
Для систем на базе Debian:
Я тестировал скрипты сверху, и они были не очень хороши. Они запускают программы, и это раздражает, потому что требуется много времени, и вам нужно закрыть программы. Я нашел решение, получающее установленные пакеты с aptitude, а затем чтение списка.
Вы можете использовать разные команды для получения разных типов установленных пакетов,
Примеры: https://askubuntu.com/info/17823/how-to-list-all-installed-packages
Два, которые я нашел лучше всего:
dpkg --get-selections # big list
aptitude search '~i!~M' -F # great list
Вы можете запустить их в терминале, чтобы проверить их.
Функция python:
import os,sys
def check_for_program(program):
if not os.path.exists("/tmp/program_list"):
os.system("aptitude search '~i!~M' -F > /tmp/program_list")
with open('/tmp/program_list') as f:
for line in f:
if program in line:
return True
return False