ฉันรู้ว่าฉันเป็นหมอผีนิดหน่อยที่นี่ แต่ฉันสะดุดในคำถามนี้และวิธีแก้ปัญหาที่ยอมรับไม่ได้ผลสำหรับฉันในทุกกรณีคิดว่าอาจเป็นประโยชน์ในการส่งต่อไป โดยเฉพาะอย่างยิ่งการตรวจจับโหมด "ปฏิบัติการ" และข้อกำหนดของการจัดหานามสกุลไฟล์ นอกจากนี้ทั้ง python3.3's shutil.which
( use PATHEXT
) และ python2.4 + 's distutils.spawn.find_executable
(เพิ่งลองเพิ่ม'.exe'
) จะทำงานในเซ็ตย่อยของเคสเท่านั้น
ดังนั้นฉันจึงเขียนเวอร์ชัน "super" (ขึ้นอยู่กับคำตอบที่ยอมรับและPATHEXT
ข้อเสนอแนะจาก Suraj) เวอร์ชันwhich
นี้ทำงานอย่างละเอียดมากขึ้นและลองใช้ชุดของเทคนิค "ความกว้าง" เป็นอันดับแรกก่อนและในที่สุดก็พยายามค้นหาที่ละเอียดยิ่งขึ้นในPATH
พื้นที่:
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
การใช้งานมีลักษณะเช่นนี้:
>>> which.which("meld")
'C:\\Program Files (x86)\\Meld\\meld\\meld.exe'
วิธีการแก้ปัญหาที่ยอมรับไม่ได้สำหรับฉันในกรณีนี้เนื่องจากมีไฟล์ที่ต้องการmeld.1
, meld.ico
, meld.doap
ฯลฯ นอกจากนี้ยังมีในไดเรกทอรีหนึ่งซึ่งถูกส่งกลับมาแทน (สมมุติตั้งแต่ lexicographically แรก) เพราะการทดสอบปฏิบัติการในคำตอบที่ได้รับการยอมรับไม่สมบูรณ์และให้ บวกเท็จ