Проверьте, существует ли программа из скрипта Python [duplicate]

This question already has an answer here:

Test if executable exists in Python? 21 answers

Как проверить, существует ли программа из скрипта Python?

Допустим, вы хотите проверить,wget или жеcurl доступны. Мы предположим, что они должны быть на пути.

Было бы лучше увидеть мультиплатформенное решение, но на данный момент Linux достаточно.

подсказки:

running the command and checking for return code is not always enough as some tools do return non 0 result even when you try --version. nothing should be visible on screen when checking for the command

Кроме того, я был бы признателен за решение, которое является более общим, какis_tool(name)

Ответы на вопрос(9)

причина в том, что он будет проверять имя программы, не пропуская абсолютный путь к программе

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
 Nicole Finnie18 мар. 2018 г., 13:13
@ GuillaumeJacquenot Спасибо, что сказали мне, у меня нет платформы Windows для тестирования.
 Guillaume Jacquenot09 нояб. 2017 г., 15:38
К сожалению, это решение не работает на платформе Windows
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
 muammar19 мая 2016 г., 10:07
Мне нравится ваша функция, но для программ, работающих в интерактивном режиме, она работает не очень хорошо. Попробуйте напримерnslookup.
 Sven Marnach26 июн. 2012 г., 17:01
Это не зависит от платформы: если вы действительно хотите копировать функциональность ОС, вам следует хотя бы использоватьos.path.join() а такжеos.pathsep.
 Sven Marnach26 июн. 2012 г., 17:05
(Я тоже редактировал вos.pathsep - в Windows,PATH разделяется точкой с запятой.)
 ryanday26 июн. 2012 г., 17:06
хорошая уловка, мои изменения перезаписали твой путь?

трами и обработать исключение, если оно не существует:

try:
    subprocess.call(["wget", "your", "parameters", "here"])
except OSError as e:
    if e.errno == os.errno.ENOENT:
        # handle file not found error.
    else:
        # Something else went wrong while trying to run `wget`
        raise

Это обычный шаблон в Python: ЭСПЦ

 Daren Thomas26 июн. 2012 г., 17:06
правильно. для программ, которые вы знаете, как использовать, это, вероятно, лучший способ сделать это. В конце концов: ожидание успеха часто приводит к более чистому коду ...
 sorin26 июн. 2012 г., 17:38
Ваше решение будет отображать вывод выполненной команды, посмотрите на мое решение, основанное на вашем, которое совершенно тихо. Stackoverflow.com / а / 11210902/99834
 Sven Marnach26 июн. 2012 г., 17:07
@ DarenThomas: Для программ, которые вы не знаете, как использовать, информация о том, существуют они или нет, не кажется слишком полезной. :)
 Sven Marnach26 июн. 2012 г., 17:53
@ SorinSbarnea: Мой подход совершенно другой. Единственная причина, по которой вы можете проверять наличие команды, заключается в том, что вы планируете ее выполнить. Моя рекомендация: не тестируйте заранее, просто запустите его и поймайте исключение, если что-то пойдет не так. Это никоим образом не загрязняет стандартный вывод или стандартный вывод, и это приведет к более чистому коду и меньшим накладным расходам.
 sorin26 июн. 2012 г., 17:08
Мне нравится твой подход, но он загрязняет stdout и stderr. Кроме того, это не функция;)

необходимого с помощью:

"который": * nix "где": 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"

или просто используйте сценарий Неда Батчелдера wh.py, который является кросс-платформенной реализацией «который»:

http: //nedbatchelder.com/code/utilities/wh_py.htm

 Photon29 янв. 2016 г., 10:07
call не выдает исключение, когда программа не существует, вместо этого вызов возвращает ненулевое значение
Решение Вопроса
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
 yadutaf12 мая 2015 г., 00:20
Обязательно откройте / dev / null дляписьм то есть:open(os.devnull, "w")
 sorin26 июн. 2012 г., 18:35
вряд ли произойдет, но ты прав, спасибо.
 Six09 дек. 2015 г., 11:33
Также просто к сведению для людей, использующих Python 3.3 и более поздних версий, вы можете использоватьsubprocess.DEVNULL скорее, чемopen(os.devnull).
 Sven Marnach26 июн. 2012 г., 17:50
Это приведет к тому, что подпроцесс будет работать неопределенно долго, если он заполняет конвейерные буферы либо stdout, либо stderr. Если вы хотите запустить процессвообщ просто чтобы проверить, существует ли он, используйте openos.devnull и использовать его как stdout и stderr.
 Sven Marnach26 июн. 2012 г., 18:44
Многие инструменты выводят информацию об использовании при вызове без параметров, которые могут легко заполнить буферы канала. В любом случае, я ошибся с первоначальным комментарием - пропустил звонокcomunnicate(), который находился за правым краем поля кода, и я не прокручивал достаточно далеко вправо. МетодPopen.communicate() старается избегать любых тупиков.

Я бы пошел на:

import distutils.spawn

def is_tool(name):
  return distutils.spawn.find_executable(name) is not None
 muammar19 мая 2016 г., 10:08
distutils.spawn хорошо работает в Linux и Mac OS X. Но в последнем случае, если вы сделаетеapp, и вы дважды щелкните, чтобы выполнить,distutils.spawn всегда возвращаетNone.

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 на чистом питоне, советую проверить здесь:http: //pypi.python.org/pypi/pycoreutil (о боже, кажется, они не снабжаютwhich. Время для дружеского подталкивания?)

ОБНОВИТ: В Windows вы можете использоватьwhere вместо тогоwhich для аналогичного эффекта.

 Daren Thomas12 июн. 2015 г., 10:35
@ nbubis, спасибо! я обновил свой ответ, чтобы отразить это.
 nbubis10 июн. 2015 г., 19:23
Это должно быть:subprocess.call(['which', 'wget'])
 Guillaume Jacquenot09 нояб. 2017 г., 15:38
К сожалению, это решение не работает на платформе Windows
 Sven Marnach26 июн. 2012 г., 17:04
Разве это не попытка запустить программу с именем"which wget", то есть с пробелом в имени файла?
 Daren Thomas26 июн. 2012 г., 20:41
@ СвенМарнах, верно! Я неправильно понял синтаксис :( о дорогой.
Shutil.which

реализация Python дляwhich, в частностиshutil.which. Он был представлен в Python 3.3 и является кроссплатформенным, поддерживает Linux, Mac и Windows. Он также доступен в Python 2.x через Whichcraft. Вы также можете просто скопировать код дляwhich прямо из какого корабляВо и вставьте его в свою программу.

def is_tool(name):
    """Check whether `name` is on PATH and marked as executable."""

    # from whichcraft import which
    from shutil import which

    return which(name) is not None
Distutils.spawn.find_executable

Другой вариант, который уже упоминался, этоdistutils.spawn.find_executable.

find_executableтрока документа @ выглядит следующим образом:

Пытается найти «исполняемый файл» в каталогах, перечисленных в «пути»

Так что, если вы обратите внимание, вы заметите, что название функции несколько вводит в заблуждение. В отличие отwhich, find_executable на самом деле не подтверждает, чтоexecutable помечается как исполняемый, только то, что он находится в PATH. Так что вполне возможно (хотя и маловероятно), чтоfind_executable означает, что программа доступна, когда ее нет.

Например, предположим, у вас есть файл/usr/bin/wget который не помечен как исполняемый. Бегwget из оболочки приведет к следующей ошибке:bash: / usr / bin / wget: в доступе отказано. 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
 Barmaley08 сент. 2016 г., 22:31
up голосуй за distutils.spawn.find_executable! Спасибо чувак
 Nick Chammas06 февр. 2016 г., 03:46
Ссылка на документы дляshutil.which(): Docs.python.org / 3 / библиотека / shutil.html # shutil.which

которое решает проблему печати в стандартный поток вывода. Если вы используете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)

Ваш ответ на вопрос