Проверьте, существует ли программа из 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

Другой вариант, который уже упоминался, - 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