Test si l'exécutable existe en Python?

en Python, y a-t-il un moyen portable et simple de tester si un programme exécutable existe?

par simple je veux dire quelque chose comme la commande which qui serait parfaite. Je ne veux pas rechercher le chemin manuellement ou quelque chose impliquant d'essayer de l'exécuter avec Popen & al et voir si elle échoue (c'est ce que je fais maintenant, mais imaginez que c'est launchmissiles )

247
demandé sur sorin 2008-12-18 08:55:36

22 réponses

la façon la plus facile à laquelle je peux penser:

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

Edit : exemple de code mis à jour pour inclure la logique de traitement du cas où l'argument fourni est déjà un chemin complet vers l'exécutable, c.-à-d. "which /bin/ls". Cela imite le comportement de la commande UNIX "which".

Modifier : mis à Jour pour utiliser le système d'exploitation.chemin.isfile() à la place de l'os.chemin.existe () per comments.

Edit : path.strip('"') semble être la mauvaise chose à faire ici. Ni Windows ni POSIX ne semblent encourager les éléments de chemin Cités.

299
répondu Jay 2017-11-10 11:08:33

je sais que c'est une question ancienne, mais vous pouvez utiliser distutils.spawn.find_executable . Cela a été documenté depuis python 2.4 et existe depuis python 1.6.

import distutils.spawn
distutils.spawn.find_executable("notepad.exe")

aussi, Python 3.3 offre maintenant shutil.which() .

267
répondu Nathan Binkert 2018-03-26 13:42:07

Python 3.3 offre maintenant shutil.qui () .

111
répondu Jan-Philip Gehrcke 2012-12-18 16:05:19

pour python 3.2 et versions antérieures:

my_command = 'ls'
any(os.access(os.path.join(path, my_command), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))

C'est une doublure de réponse de Jay , aussi ici comme une lambda func:

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

ou enfin, en retrait en fonction:

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

pour python 3.3 et suivants:

import shutil

command = 'ls'
shutil.which(command) is not None

Comme un one-liner Jan-Philip Gehrcke Réponse :

cmd_exists = lambda x: shutil.which(x) is not None

comme un def:

def cmd_exists(cmd):
    return shutil.which(cmd) is not None
25
répondu ThorSummoner 2017-05-23 10:31:29

n'oubliez pas de spécifier l'extension du fichier sur windows. Sinon, vous devez écrire un is_exe très compliqué pour windows en utilisant PATHEXT variable d'environnement. Vous pouvez simplement utiliser FindPath .

OTOH, Pourquoi cherchez-vous l'exécutable? Le système d'exploitation le fera pour vous dans le cadre de popen call & soulèvera une exception si l'exécutable n'est pas trouvé. Tout ce que vous devez faire est d'attraper le corriger l'exception pour un OS donné. Notez que sur Windows, subprocess.Popen(exe, shell=True) échouera silencieusement si exe n'est pas trouvé.


l'Incorporation PATHEXT dans le ci-dessus la mise en œuvre de which (Jay):

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
16
répondu Suraj 2017-11-21 12:08:17

Pour *nix, les plates-formes (Linux et OS X)

Cela semble fonctionner pour moi:

édité pour travailler sur Linux, grâce à Mestreion

def cmd_exists(cmd):
    return subprocess.call("type " + cmd, shell=True, 
        stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0

ce que nous faisons ici est d'utiliser la commande type et de vérifier le code de sortie. S'il n'y a pas de telle commande, type sortira avec 1 (ou un code de statut non-zéro de toute façon).

le un peu sur stdout et stderr, c'est juste pour réduire au silence la sortie de la commande type , puisque nous ne sommes intéressés que par le code d'état de sortie.

exemple d'usage:

>>> cmd_exists("jsmin")
True
>>> cmd_exists("cssmin")
False
>>> cmd_exists("ls")
True
>>> cmd_exists("dir")
False
>>> cmd_exists("node")
True
>>> cmd_exists("steam")
False
15
répondu hasen 2017-05-23 12:26:20

voir os.module de chemin pour certaines fonctions utiles sur les noms de chemin. Pour vérifier si un fichier existant est exécutable, utilisez os.accès (chemin, mode) , avec l'os.Mode X_OK.

os.X_OK

valeur à inclure dans le paramètre mode d'accès() pour déterminer si le chemin peut être exécuté.

EDIT: which() il manque un indice aux implémentations-utiliser os.path.join() pour construire des noms de fichiers complets.

8
répondu gimel 2008-12-18 13:31:26

sur la base qu'il est plus facile de demander pardon que la permission je voudrais juste essayer de l'utiliser et attraper l'erreur (OSError dans ce cas - J'ai vérifié pour le fichier n'existe pas et le fichier n'est pas exécutable et ils donnent tous les deux OSError).

cela aide si l'exécutable a quelque chose comme un drapeau --version qui est un no-op rapide.

import subprocess
myexec = "python2.8"
try:
    subprocess.call([myexec, '--version']
except OSError:
    print "%s not found on path" % myexec

Ce n'est pas une solution générale, mais sera le moyen le plus facile pour beaucoup de les cas d'utilisation-ceux où le code doit chercher un seul exécutable bien connu.

5
répondu Hamish Downer 2012-07-26 08:06:30

je sais que je suis un peu nécromancien ici, mais je suis tombé sur cette question et la solution acceptée n'a pas fonctionné pour moi pour tous les cas pensé qu'il pourrait être utile de soumettre de toute façon. En particulier, la détection de mode" exécutable", et l'exigence de fournir l'extension de fichier. De plus, les deux python3.3 shutil.which (utilise PATHEXT ) et python2.4 + 's distutils.spawn.find_executable (vient d'essayer d'ajouter '.exe' ) ne fonctionnent que dans un sous-ensemble de cas.

J'ai donc écrit une version" super "(basée sur la réponse acceptée, et la suggestion PATHEXT de Suraj). Cette version de which fait la tâche un peu plus à fond, et tente une série de "broadphase" largeur-premières techniques d'abord, et éventuellement des recherches plus fines sur le PATH espace:

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
"1519120920 Utilisation" ressemble à ceci:

>>> which.which("meld")
'C:\Program Files (x86)\Meld\meld\meld.exe'

la solution acceptée n'a pas fonctionné pour moi dans ce cas, car il des dossiers comme meld.1 , meld.ico , meld.doap , etc également dans le répertoire, dont l'un a été retourné à la place (probablement depuis lexicographic première) parce que le test exécutable dans la réponse acceptée était incomplète et donnant des faux positifs.

4
répondu Preet Kukreti 2013-08-31 11:04:16

le meilleur exemple devrait être le module bulit-in de Python shutil.qui () en Python 3. Le lien est https://hg.python.org/cpython/file/default/Lib/shutil.py

4
répondu liuyix 2014-11-13 04:17:29

j'ai trouvé quelque chose dans StackOverflow qui a résolu le problème pour moi. Cela fonctionne à condition que l'exécutable ait une option (comme --help ou --version) qui affiche quelque chose et renvoie un statut de sortie de zéro. Voir supprimer la sortie dans les appels Python vers les exécutables - le" résultat " à la fin de l'extrait de code dans cette réponse sera zéro si l'exécutable est dans le chemin, sinon il est plus probable d'être 1.

2
répondu Somesh 2017-05-23 10:31:29

cela semble assez simple et fonctionne à la fois en python 2 et 3

try: subprocess.check_output('which executable',shell=True)
except: sys.exit('ERROR: executable not found')
2
répondu jaap 2013-10-13 22:43:51

si vous avez bash et une fonction sh ( subprocess.Popen( ... ).communicate() ),

utiliser le bash builtin type :

type -p ls  =>  /bin/ls
type -p nonesuch  =>  ""
1
répondu denis 2009-04-28 10:13:32

une question importante est " pourquoi avez-vous besoin de tester si l'exécutable existe?"Peut-être que vous ne le faites pas? ;- )

récemment, j'ai eu besoin de cette fonctionnalité pour lancer viewer pour le fichier PNG. Je voulais itérer sur quelques visionneuses prédéfinies et lancer la première qui existe. Heureusement, je suis tombé sur os.startfile . C'est beaucoup mieux! Simple, portable et utilise le par défaut viewer sur le système:

>>> os.startfile('yourfile.png')

mise à Jour: j'ai eu tort à propos de os.startfile être portable... C'est Windows uniquement. Sur Mac, vous devez exécuter la commande open . Et xdg_open sur Unix. Il y a un problème Python sur l'ajout du Support Mac et Unix pour os.startfile .

1
répondu ash 2009-08-29 18:13:59

vous pouvez essayer le lib externe appelé "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
1
répondu jung rhew 2014-11-06 18:05:55

a ajouté le support de windows

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
1
répondu wukong 2015-04-17 04:06:02

vous pouvez dire si un fichier existe avec le module os. un exécutable en particulier semble tout à fait inapplicable compte tenu de beaucoup de choses sont exécutables sur nix qui ne sont pas sur windows et vice versa.

0
répondu Dustin Getz 2008-12-18 06:04:51

il semblerait que le évident le choix est" qui", en analysant les résultats via popen, mais vous pourriez le simuler autrement en utilisant la classe os. En pseudopython, il ressemblerait à ceci:

for each element r in path:
    for each file f in directory p:
        if f is executable:
           return True
0
répondu Charlie Martin 2008-12-18 06:27:05

donc en gros, vous voulez trouver un fichier dans le système de fichiers monté (pas nécessairement dans les répertoires chemin seulement) et vérifier s'il est exécutable. Cela se traduit par le plan suivant:

  • énumérer tous les fichiers dans les systèmes de fichiers montés localement
  • résultats du match avec un modèle de nom de
  • pour chaque fichier trouvé, Vérifiez s'il est exécutable

je dirais, faire cela d'une manière portable exigera beaucoup de la puissance de calcul et de temps. Est-ce vraiment ce dont vous avez besoin?

0
répondu zgoda 2008-12-18 11:34:02

il y a un which.py script dans une distribution Python standard (par exemple sur Windows '\PythonXX\Tools\Scripts\which.py' ).

EDIT: which.py dépend de ls par conséquent, il n'est pas multi-plateforme.

0
répondu jfs 2008-12-22 08:14:25

Aucun des exemples précédents ne fonctionne sur toutes les plateformes. Habituellement, ils ne fonctionnent pas sur Windows parce que vous pouvez exécuter sans l'extension de fichier et que vous pouvez enregistrer une nouvelle extension. Par exemple sur Windows si python est bien installé, il suffit d'exécuter 'file.py" et cela fonctionnera.

la seule solution valable et portable que j'avais était d'exécuter la commande et de voir le code d'erreur. Tout exécutable décent devrait avoir un ensemble d'appel des paramètres qui ne feront rien.

0
répondu sorin 2009-07-22 16:25:00

utilisant la bibliothèque de tissu 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
-3
répondu frodopwns 2015-12-03 20:58:33