Làm cách nào để tìm đường dẫn cho tệp thực thi?


81

Tôi cần thiết lập môi trường với đường dẫn đến tệp nhị phân. Trong shell, tôi có thể sử dụng whichđể tìm đường dẫn. Có tương đương trong python không? Đây là mã của tôi.

cmd = ["which","abc"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
res = p.stdout.readlines()
if len(res) == 0: return False
return True

Ngay cả trong chính trình bao, whichbản thân nó không phải là một lựa chọn tốt để phát hiện nếu một lệnh được cài đặt. Tham khảo
kojiro

Câu trả lời:


93

6
+1, điều này thật tuyệt và là một phần của thư viện tiêu chuẩn! Hãy nhận biết rằng nó rất hạn chế trên Windows - nó không phân tích cú pháp PATHEXT, thay vào đó nó giả định nó phải được tìm kiếm một phần mở rộng '.exe' (thiếu các tập tin batch vv)
orip

2
Hãy lưu ý rằng nó không kiểm tra xem tệp có thực thi được hay không.
temoto

1
Điều này không hoạt động đối với tôi trên 2.7 hoặc 3.6. Nó đã xảy ra lỗi không tìm thấy mô-đun sinh sản.
GreenMatt

@temoto Tuy nhiên, nó sẽ không tìm thấy tệp dll (mà tôi có thể kiểm tra PATHthông qua where.exe) cho tôi trên Windows.
jpmc26

@GreenMatt, vừa thử vào ngày 3.7, hoạt động tốt. Như đã đề cập bởi những người khác, đừng quên chạy import distutils.spawntrước.
zonksoft

78

Tôi biết đây là một câu hỏi cũ hơn, nhưng nếu bạn tình cờ sử dụng Python 3.3+, bạn có thể sử dụng shutil.which(cmd). Bạn có thể tìm tài liệu tại đây . Nó có lợi thế là nằm trong thư viện tiêu chuẩn.

Một ví dụ sẽ như vậy:

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

13

Không có lệnh để làm điều đó, nhưng bạn có thể lặp lại environ["PATH"]và xem tệp có tồn tại hay không, đó thực sự là những gì which.

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

Chúc may mắn!


1
Bạn cần thận trọng khi đưa ra các giả định về ký tự pathsep.
John Percival Hackworth

và dấu phân cách đường dẫn, nhưng đây chỉ là một điểm khó hiểu. Chúc may mắn!
Gonzalo Larralde

sử dụng os.path.septhay vì /os.pathsepthay vì:
djhaskin987

2
Không sử dụng '+', sử dụng os.path.join. Xem thêm các câu trả lời được bình chọn cao hơn cho việc triển khai stdlib (bản phân phối) và một nền tảng độc lập hơn với dự án Twisted.
benjaoming,

cảm ơn vì os.path.join. Việc thực hiện xoắn là hoàn toàn bị cô lập, dường như không có bất kỳ liên phụ thuộc với phần còn lại của dự án, như vậy là một thực hiện nó là tốt hơn nhiều (hơn tôi ít nhất)
Gonzalo Larralde

13

Cảm ơn, tôi sẽ sử dụng nó.
jonaprieto

Vấn đề là nó yêu cầu cài đặt mô-đun Twisted, có khả năng gây khó khăn trên Windows (ngay cả với bánh xe của Christoph Gohlke).
Agi Hammerthief

1
Liên kết đến triển khai Twisted bị hỏng. Có vẻ như nó có thể được tìm thấy ở đây: github.com/twisted/twisted/blob/trunk/src/twisted/python/…
rkersh

4

Bạn có thể thử một cái gì đó như sau:

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

Bạn cần phải thực hiện PATHEXTvào tài khoản cũng
orip

2
Trên máy tính Windows, tôi nghi ngờ rằng bạn có thể sẽ tìm kiếm tên chính xác của tệp, thay vì giả sử các phần mở rộng. Như đã nói, sẽ không khó để thêm một vòng lặp bên trong lặp qua các thành viên của PATHEXT.
John Percival Hackworth

3

Nếu bạn sử dụng shell=True, thì lệnh của bạn sẽ được chạy qua hệ thống shell, nó sẽ tự động tìm mã nhị phân trên đường dẫn:

p = subprocess.Popen("abc", stdout=subprocess.PIPE, shell=True)

Ngay cả khi không có shell=Truenó vẫn được tra cứu trong đường dẫn, nhưng nó không hữu ích nếu bạn muốn tìm thấy lệnh nào có thể tồn tại.
Antti Haapala

3

Đây là lệnh tương đương với lệnh which, không chỉ kiểm tra xem tệp có tồn tại hay không mà còn kiểm tra xem nó có thực thi được không:

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

0

Đây là phiên bản một dòng của các câu trả lời trước đó:

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)

được sử dụng như vậy:

>>> which("ls")
'/bin/ls'

Điều này dường như không hoạt động trong Python2 , TypeError: list object is not an iterator.
Gibbsoft
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.