2012-06-26 7 views
25

Как проверить, существует ли программа из сценария python?Проверьте, существует ли программа из сценария python

Предположим, вы хотите проверить, имеются ли wget или curl. Мы предположим, что они должны идти в путь.

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

Подсказки:

  • , выполнив команду и проверки кода возврата не всегда достаточно, поскольку некоторые инструменты делают вернуть нон 0 результат даже при попытке --version.
  • ничего не должно быть видно на экране при проверке команды

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

+0

возможно дубликат [Тест, если исполняемый файл существует в Python?] (http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python) –

ответ

8
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

. Это оставило бы подпроцесс, работающий неопределенно долго, если он заполняет буферы канала как stdout, так и stderr. Если вы хотите полностью запустить процесс *, чтобы проверить, существует ли он, вы должны использовать открытый 'os.devnull' и использовать его как stdout и stderr. –

+0

вряд ли случится, но вы правы, спасибо. – sorin

+0

Многие инструменты выводят информацию об использовании при вызове без параметров, которые могут легко заполнять буферы. В любом случае, я был не в порядке с моим первоначальным комментарием - я пропустил вызов 'comunnicate()', который был выше допустимого поля кода, и я не прокрутил достаточно далеко вправо. Метод 'Popen.communicate()' позаботится о том, чтобы избежать каких-либо взаимоблокировок. –

3

я бы, вероятно, раскошеливаться which wget или which curl и проверки что результат заканчивается именем используемой вами программы. Магия unix :)

На самом деле все, что вам нужно сделать, это проверить код возврата which. Так что ... с помощью нашего испытанного subprocess модуля:

import 
rc = subprocess.call(['which', 'wget']) 
if rc == 0: 
    print 'wget installed!' 
else: 
    print 'wget missing in path!' 

Обратите внимание, что я тестировал это на окна с Cygwin ... Если вы хотите, чтобы выяснить, как реализовать which в чистом питоне, я предлагаю вам проверить здесь: http://pypi.python.org/pypi/pycoreutils (ой дорогой - кажется, что они не обеспечивают which время для дружеского толчка.?)

UPDATE: в Windows вы можете использовать where вместо which для подобного эффекта.

+1

Не попытается ли запустить программу с именем '' which wget ", то есть с помощью пространство в имени файла? –

+0

@SvenMarnach, правильно! –

+1

Это должно быть: 'subprocess.call (['which', 'wget'])' – nbubis

31

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

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: EAFP

+0

для программ, которые вы знаете, как использовать, это, вероятно, лучший способ сделать это. В конце концов: ожидание успеха часто приводит к более чистому коду ... –

+1

@ DarenThomas: для программ вы не знаю, как использовать, информация о том, существуют ли они или нет, не кажется слишком полезной. :) –

+0

Мне нравится ваш подход, но он загрязняет stdout и stderr. Кроме того, это не функция;) – sorin

1
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 
+0

Это не зависит от платформы: если вы действительно хотите реплицировать функциональность ОС, вы должны, по крайней мере, использовать 'os.path.join()' и 'os.pathsep'. –

+0

(Я также отредактировал в 'os.pathsep' - в Windows,' PATH' разделен точкой с запятой.) –

+0

Хороший улов, изменилось ли мое редактирование на pathsep? – ryanday

14

Вы можете использовать подпроцесс вызов двоичном необходимого с:

  • «который»: * Никс
  • «где»: 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's wh.ру сценарий, то есть «который» крест реализации платформы:

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

+0

вызов не генерирует исключение, когда программа не существует, вместо этого вызов возвращает ненулевое значение – Photon

0

Незначительная модификация @ SvenMarnach код, который рассматривается вопрос о печати в стандартный выходной поток. Если вы используете функцию subprocess.check_output(), а не subprocess.call(), вы можете обрабатывать строку, которая обычно печатается стандартным образом в вашем коде, и по-прежнему захватывать исключения и код состояния выхода.

Если вы хотите, чтобы подавить стандартный поток вывода в терминале, не печатать зЬй из строки, возвращаемые из 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() добавляет дополнительный символ новой строки к строке. Если вы хотите избавиться от этого (и писать зУю ошибку в станде ERR поток вместо станда из потока, как показаны с печатью() заявления выше), используйте sys.stdout.write(string) и sys.stderr.write(string) вместо печать():

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) 
-1

Для систем на базе Debian:

Я протестировал скрипты сверху, и они были не очень хороши. Они запускают программы, и это раздражает, потому что требуется много времени, и вам нужно закрыть программы. Я нашел решение, получающее установленные пакеты с aptitude, а затем чтение списка.

Вы можете использовать различные виды команд, чтобы получить различные виды Exemples «Установленные пакеты»: https://askubuntu.com/questions/17823/how-to-list-all-installed-packages

Два, что я нашел самое лучшее было:

dpkg --get-selections   # big list 
aptitude search '~i!~M' -F  # great list 

Вы можете запустить их в чтобы проверить их.


Функция питон:

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 
+2

Это работает только в системах на базе Debian, и неудачно произойдет, когда пакеты будут переименованы, что иногда происходит. –

10

я бы на:

import distutils.spawn 

def is_tool(name): 
    return distutils.spawn.find_executable(name) is not None 
+0

'distutils.spawn' отлично работает в Linux и Mac OS X. Но в последнем случае, если вы создаете' приложение', и вы делаете двойной щелчок для выполнения, 'distutils.spawn' всегда возвращает' None'. – muammar

23

shutil.which

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

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 «S выглядит следующим образом:

Tries to find 'executable' in the directories listed in 'path'

Так что, если вы обратите внимание, то заметите, что имя функции несколько вводит в заблуждение. В отличие от 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 
+0

Ссылка на документы для 'shutil.which()': https://docs.python.org/3/library/shutil.html#shutil.which –

+0

голосование за distutils.spawn.find_executable! Спасибо чувак! – Barmaley

2

Я бы изменить @ ответ Сорина следующим образом, причина в том, что бы проверить название программы без прохождения абсолютного пути к программе

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 
+0

К сожалению, это решение не работает для платформы Windows –

Смежные вопросы