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
)
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.
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()
.
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
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
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
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.
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.
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.
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
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.
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')
si vous avez bash
et une fonction sh
( subprocess.Popen( ... ).communicate()
),
utiliser le bash
builtin type
:
type -p ls => /bin/ls
type -p nonesuch => ""
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
.
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
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
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.
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
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?
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.
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