Pythonでは、実行可能プログラムが存在するかどうかをテストするための移植可能な簡単な方法はありますか?
簡単に言うwhich
と、完璧なコマンドのようなものです。PATHを手動で検索したり、Popen
&al でPATHを実行したりして失敗するかどうかを確認したくありません(これは今私がやっていることですが、想像してみてくださいlaunchmissiles
)
which
、サードパーティのモジュールは、:code.activestate.com/pypm/which
Pythonでは、実行可能プログラムが存在するかどうかをテストするための移植可能な簡単な方法はありますか?
簡単に言うwhich
と、完璧なコマンドのようなものです。PATHを手動で検索したり、Popen
&al でPATHを実行したりして失敗するかどうかを確認したくありません(これは今私がやっていることですが、想像してみてくださいlaunchmissiles
)
which
、サードパーティのモジュールは、:code.activestate.com/pypm/which
回答:
私が考えることができる最も簡単な方法:
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
編集:コードサンプルを更新して、提供された引数が実行可能ファイルへのフルパス、つまり "which / bin / ls"である場合を処理するロジックを含めました。これは、UNIXのwhichコマンドの動作を模倣しています。
編集:コメントごとにos.path.exists()ではなくos.path.isfile()を使用するように更新されました。
編集:path.strip('"')
ここで行うのは間違っているようです。WindowsもPOSIXも、引用されたPATHアイテムを奨励していないようです。
PATHEXT
ためのenv VAR command
として有効であるようcommand.com
であるとしてscript
対script.bat
これは古い質問であることは知っていますが、を使用できますdistutils.spawn.find_executable
。これはpython 2.4以降に文書化され、python 1.6以降に存在しています。
import distutils.spawn
distutils.spawn.find_executable("notepad.exe")
また、Python 3.3ではが提供されるようになりましたshutil.which()
。
win32
、distutils.spawn.find_executable
実装がだけを探し.exe
にセットを検索するための拡張機能のリストを使用してではなく%PATHEXT%
。それは素晴らしいことではありませんが、誰かが必要とするすべてのケースでうまくいくかもしれません。
from distutils import spawn
php_path = spawn.find_executable("php")
distutils.spawn
OS X 10.10上のPython 2.7.6の私のシステムで(/ usr / bin / pythonを)インストールし、私が手::確実に入手できないAttributeError: 'module' object has no attribute 'spawn'
、不思議なことは、Pythonの同じバージョンと同じマシン上で動作しますが、しかしからvirtualenvインストール。
import distutils.spawn
、必ず、またはfrom distutils import spawn
構文に従ってくださいimport distutils
。それ以外の場合はアクセスできない可能性AttributeError
があり、そこにある場合でも上記を取得します。
Python 3.3で、shutil.which()が提供されるようになりました。
my_command = 'ls'
any(os.access(os.path.join(path, my_command), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))
これは、Jay's Answerの 1行であり、ラムダ関数としてもここにあります。
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')
または最後に、関数としてインデント:
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)
)
import shutil
command = 'ls'
shutil.which(command) is not None
Jan-Philip Gehrcke Answerのワンライナーとして:
cmd_exists = lambda x: shutil.which(x) is not None
defとして:
def cmd_exists(cmd):
return shutil.which(cmd) is not None
x
必要がありますcmd
os.path.join(path, cmd)
ファイルかどうかを確認するためのテストも追加する必要がありますか?結局のところ、ディレクトリには実行可能ビットを設定することもできます...
mkdir -p -- "$HOME"/bin/dummy && PATH="$PATH":"$HOME"/bin && python -c 'import os; print any(os.access(os.path.join(path, "dummy"), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))' && rmdir -- "$HOME"/bin/dummy
and os.path.isfile(...)
適切な場所に単純なものを追加するだけでそれを修正できます
Windowsでファイル拡張子を指定することを忘れないでください。それ以外の場合は、環境変数is_exe
を使用して、Windowsに対して非常に複雑なコードを記述する必要がありPATHEXT
ます。FindPathを使用したいだけかもしれません。
OTOH、なぜあなたは実行ファイルを探すのに面倒なのですか?オペレーティングシステムは、popen
呼び出しの一部としてそれを実行し、実行可能ファイルが見つからない場合は例外を発生させます。必要なのは、特定のOSの正しい例外をキャッチすることだけです。Windowsでは、subprocess.Popen(exe, shell=True)
がexe
見つからない場合は警告なしで失敗することに注意してください。
(ジェイの答えで)のPATHEXT
上記の実装に組み込むwhich
:
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
yield
inを巧みに使用ext_candidates
することで、そのキーワードがどのように機能するかをよりよく理解できました
これは私のために働いているようです:
Mestreionのおかげで、Linuxで動作するように編集されました
def cmd_exists(cmd):
return subprocess.call("type " + cmd, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0
ここでは、組み込みコマンドを使用しtype
て終了コードを確認しています。そのようなコマンドがない場合type
、1(またはゼロ以外のステータスコード)で終了します。
stdoutとstderrのビットtype
は、終了ステータスコードのみに関心があるため、コマンドの出力を無音にすることです。
使用例:
>>> cmd_exists("jsmin")
True
>>> cmd_exists("cssmin")
False
>>> cmd_exists("ls")
True
>>> cmd_exists("dir")
False
>>> cmd_exists("node")
True
>>> cmd_exists("steam")
False
type
実行可能ファイルではなくシェルに組み込まれているため、ここではsubprocess.call()
失敗します。
OSError: [Errno 2] No such file or directory
ます。多分Mac type
で実際のコマンド
shell=True
と置き換える["type", cmd]
ために"type " + cmd
パス名に関するいくつかの便利な関数については、os.pathモジュールを参照してください。既存のファイルが実行可能かどうかを確認するには、os.X_OKモードでos.access(path、mode)を使用します。
os.X_OK
パスを実行できるかどうかを決定するためにaccess()のモードパラメータに含める値。
編集:提案which()
された実装には1つの手掛かりがありません- os.path.join()
完全なファイル名を構築するために使用します。
許可よりも許しを求める方が簡単なので、私はそれを使用してエラーをキャッチしようとします(この場合はOSError-ファイルが存在しないことを確認し、ファイルが実行可能ではなく、どちらもOSErrorを与えます)。
これは、実行可能ファイルに--version
フラグのような何かがあり、すぐに何もしない場合に役立ちます。
import subprocess
myexec = "python2.8"
try:
subprocess.call([myexec, '--version']
except OSError:
print "%s not found on path" % myexec
これは一般的なソリューションではありませんが、多くのユースケース(コードが単一の既知の実行可能ファイルを探す必要がある場合)の最も簡単な方法です。
--version
という名前のプログラムを呼び出すことも危険launchmissiles
です。
launchmissies
する場合を除いて、ミサイルを発射したくないのになぜ存在するのか知りたいのですか?それを実行し、終了ステータス/例外に基づいて行動する方が良い
git
ブラインドで実行したくない場合のためのスタブ実行可能ファイルもあります。
私はここで少しネクロマンサーになっていることはわかっていますが、この質問に出くわし、すべてのケースで受け入れられた解決策がうまくいきませんでした。特に、「実行可能」モードの検出、およびファイル拡張子の指定の要件。さらに、python3.3 shutil.which
(使用PATHEXT
)とpython2.4 + distutils.spawn.find_executable
(追加しようとする'.exe'
だけ)は、ケースのサブセットでのみ機能します。
そこで私は「スーパー」バージョンを作成しました(受け入れられた回答と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
、なども受け入れ答えで実行可能なテストが不完全と与えていたので(辞書順で最初以来、おそらく)代わりに返されたそのうちの一つのディレクトリ、中偽陽性。
最良の例は、Python 3のpython bulit-inモジュールshutil.which()です。リンクはhttps://hg.python.org/cpython/file/default/Lib/shutil.pyです。
StackOverflowで問題を解決するものを見つけました。これは、実行可能ファイルに何かを出力し、ゼロの終了ステータスを返すオプション(--helpや--versionなど)がある場合に機能します。実行可能ファイルへのPython呼び出しで出力を抑制するを参照してください。実行可能ファイルがパスにある場合、この回答のコードスニペットの最後の「結果」はゼロになり、そうでない場合は1になる可能性が高くなります。
これは十分にシンプルに思え、Python 2と3の両方で機能します
try: subprocess.check_output('which executable',shell=True)
except: sys.exit('ERROR: executable not found')
command -v executable
またはtype executable
を使用して、普遍的です。Macでは、期待した結果が返されない場合があります。
重要な質問は、「なぜ実行可能ファイルが存在するかどうかをテストする必要があるのか?」です。多分あなたはしませんか?;-)
最近、PNGファイルのビューアを起動するためにこの機能が必要でした。いくつかの事前定義されたビューアを反復処理して、存在する最初のビューアを実行したいと思っていました。幸いにも、私は出会いましたos.startfile
。それははるかに優れています!シンプルで移植性があり、システムのデフォルトビューアーを使用します。
>>> os.startfile('yourfile.png')
更新:os.startfile
移植性に問題がありました... Windowsのみです。Macでは、open
コマンドを実行する必要があります。そしてxdg_open
Unixで。MacおよびUnixのサポートの追加に関するPythonの問題がありos.startfile
ます。
"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
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
popenを介して結果を解析する「どちらか」を選択するのは明らかなようですが、それ以外の場合はosクラスを使用してシミュレートできます。疑似Pythonでは、次のようになります。
for each element r in path:
for each file f in directory p:
if f is executable:
return True
which
コマンドはありません。UnxUtilsバージョンがありますが、拡張機能を知っている/指定する必要があります。そうしないと、プログラムが見つかりません。
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
which(1)
すべてのシステムに存在しないものに依存しています。