¿Cómo puedo encontrar la ruta de un ejecutable?

81

Necesito configurar el entorno con la ruta a un binario. En el caparazón, puedo usar whichpara encontrar la ruta. ¿Existe un equivalente en Python? Este es mi codigo.

cmd = ["which","abc"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
res = p.stdout.readlines()
if len(res) == 0: return False
return True
prosseek
fuente
Incluso en el propio shell, whichno es una buena opción para detectar si un comando está instalado. Referencia
kojiro
¿Posible duplicado de Prueba si existe ejecutable en Python?
Bernhard

Respuestas:

93

Hay distutils.spawn.find_executable().

zonksoft
fuente
6
+1, ¡esto es genial y es parte de la biblioteca estándar! Tenga en cuenta que es muy limitado en Windows: no analiza PATHEXT, sino que asume que debería buscar una extensión '.exe' (faltan archivos por lotes, etc.)
orip
2
Tenga en cuenta que no comprueba si el archivo es ejecutable.
temoto
1
Esto no funcionó para mí en 2.7 o 3.6. Dio un error de que no se encontró el módulo de generación.
GreenMatt
@temoto Y, sin embargo, a pesar de eso, no encontrará un archivo dll (que pueda verificar a PATHtravés de where.exe) para mí en Windows.
jpmc26
@GreenMatt, recién probado en 3.7, funciona bien. Como lo mencionaron otros, no olvide ejecutar import distutils.spawnprimero.
zonksoft
78

Sé que esta es una pregunta anterior, pero si está usando Python 3.3+, puede usar shutil.which(cmd). Puede encontrar la documentación aquí . Tiene la ventaja de estar en la biblioteca estándar.

Un ejemplo sería así:

>>> import shutil
>>> shutil.which("bash")
'/usr/bin/bash'
iLoveTux
fuente
13

No hay un comando para hacer eso, pero puede iterar environ["PATH"]y ver si el archivo existe, que es en realidad lo que whichhace.

import os

def which(file):
    for path in os.environ["PATH"].split(os.pathsep):
        if os.path.exists(os.path.join(path, file)):
                return os.path.join(path, file)

    return None

¡Buena suerte!

Gonzalo Larralde
fuente
1
Debes tener cuidado al hacer suposiciones sobre el carácter pathsep.
John Percival Hackworth
y separador de ruta, pero esto es solo una peculiaridad para hacer un punto. ¡Buena suerte!
Gonzalo Larralde
uso en os.path.seplugar de /y en os.pathseplugar de:
djhaskin987
2
No use '+', use os.path.join. Vea más respuestas mejoradas para una implementación stdlib (distutils) y una plataforma más independiente del proyecto Twisted.
benjaoming
gracias por os.path.join. La implementación retorcida está completamente aislada, no parece tener ninguna interdependencia con el resto del proyecto, por lo que como implementación es mucho mejor (que la mía al menos)
Gonzalo Larralde
4

Puede probar algo como lo siguiente:

import os
import os.path
def which(filename):
    """docstring for which"""
    locations = os.environ.get("PATH").split(os.pathsep)
    candidates = []
    for location in locations:
        candidate = os.path.join(location, filename)
        if os.path.isfile(candidate):
            candidates.append(candidate)
    return candidates
John Percival Hackworth
fuente
También debe tener PATHEXTen cuenta
orip
2
En una máquina con Windows, sospecho que probablemente buscaría el nombre exacto del archivo, en lugar de asumir las extensiones. Dicho esto, no sería difícil agregar un bucle interno que itera sobre los miembros de PATHEXT.
John Percival Hackworth
3

Si lo usa shell=True, su comando se ejecutará a través del shell del sistema, que encontrará automáticamente el binario en la ruta:

p = subprocess.Popen("abc", stdout=subprocess.PIPE, shell=True)
Greg Hewgill
fuente
Incluso sin shell=Trueél, se busca en la ruta, pero no ayuda si desea encontrar cuál de los posibles comandos existe.
Antti Haapala
3

Este es el equivalente del comando which, que no solo verifica si el archivo existe, sino también si es ejecutable:

import os

def which(file_name):
    for path in os.environ["PATH"].split(os.pathsep):
        full_path = os.path.join(path, file_name)
        if os.path.exists(full_path) and os.access(full_path, os.X_OK):
            return full_path
    return None
o9000
fuente
0

Aquí hay una versión de una línea de respuestas anteriores:

import os
which = lambda y: next(filter(lambda x: os.path.isfile(x) and os.access(x,os.X_OK),[x+os.path.sep+y for x in os.getenv("PATH").split(os.pathsep)]),None)

usado así:

>>> which("ls")
'/bin/ls'
Anónimo
fuente
Esto no parece funcionar en python2, TypeError: list object is not an iterator.
Gibbsoft