检查python脚本中是否存在程序

时间:2012-06-26 14:54:34

标签: python

如何从python脚本检查程序是否存在?

假设您要检查wgetcurl是否可用。我们假设他们应该走在路上。

最好看一个多平台解决方案,但目前,Linux就足够了。

提示:

  • 运行命令并检查返回代码并不总是足够,因为即使您尝试--version,某些工具也会返回非0结果。
  • 检查命令时,屏幕上看不到任何内容

另外,我会感谢更为通用的解决方案,例如is_tool(name)

9 个答案:

答案 0 :(得分:53)

shutil.which

让我推荐一个尚未讨论过的选项:which的Python实现,特别是shutil.which。它是在Python 3.3中引入的,是跨平台的,支持Linux,Mac和Windows。它也可以通过whichcraft在Python 2.x中使用。您也可以直接从which中删除def is_tool(name): """Check whether `name` is on PATH and marked as executable.""" # from whichcraft import which from shutil import which return which(name) is not None 的代码并将其插入到您的程序中。

distutils.spawn.find_executable

distutils.spawn.find_executable

已经提到的另一个选项是find_executable

which的文档字符串如下:

  

试图找到可执行的'在'路径'

中列出的目录中

因此,如果您注意,您会注意到该功能的名称有些误导。与find_executable不同,executable实际上并未验证find_executable是否已标记为可执行,只是它位于PATH上。因此/usr/bin/wget表明程序可用时完全可能(但不太可能)。

例如,假设您有一个未标记为可执行文件的文件wget。从shell运行which('wget') is not None将导致以下错误: bash:/ usr / bin / wget:Permission denied find_executable('wget') is not None将返回False,但find_executable将返回True。您可以使用任何一种功能,但这只是def is_tool(name): """Check whether `name` is on PATH.""" from distutils.spawn import find_executable return find_executable(name) is not None 需要注意的事项。

public class TableRowChess extends TableRow {

private Context context;

private int numberOfColumns;
private int rowNumber;

private String[][] solution;

public TableRowChess(Context context, int numberOfColumns, int rowNumber, String[][] solution) {
    super(context);

    this.context = context;
    this.numberOfColumns = numberOfColumns;
    this.rowNumber = rowNumber;
    this.solution = solution;

    initializeTableRow();
    initializeTextViews();
}


private void initializeTableRow(){
    this.setLayoutParams(new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, (float) numberOfColumns));
}

private void initializeTextViews(){
    TableRow.LayoutParams  params = new TableRow.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);

    for(int i = 0; i < numberOfColumns; i ++){
        SquareTextView tv = new SquareTextView(context);

        tv.setLayoutParams(params);
        tv.setGravity(Gravity.CENTER);
        tv.setBackgroundResource(getCorrectBackground(i));
        tv.setHeight(tv.getLayoutParams().width);
        tv.setText(solution[rowNumber][i]);
        tv.setTextAppearance(context, android.R.style.TextAppearance_Medium);
        tv.setTypeface(null, Typeface.BOLD);

        this.addView(tv);
    }
}

private int getCorrectBackground(int columnNumber){
    if((rowNumber % 2) == 0){
        if((columnNumber % 2) == 0){
            return R.drawable.square_white;
        } else {
            return R.drawable.square_brown;
        }
    } else {
        if((columnNumber % 2) == 0){
            return R.drawable.square_brown;
        } else {
            return R.drawable.square_white;
        }
    }
}
}

答案 1 :(得分:38)

最简单的方法是尝试使用所需的参数运行程序,并处理异常(如果不存在):

try:
    subprocess.call(["wget", "your", "parameters", "here"])
except OSError as e:
    if e.errno == os.errno.ENOENT:
        # handle file not found error.
    else:
        # Something else went wrong while trying to run `wget`
        raise

这是Python中的常见模式:EAFP

答案 2 :(得分:15)

您可以使用对所需二进制文件的子进程调用:

  • “which”:* nix
  • “where”:Win 2003及更高版本(Xp有一个插件)

获取可执行文件路径(假设它在环境路径中)。

import os 
import platform
import subprocess

cmd = "where" if platform.system() == "Windows" else "which"
try: 
    subprocess.call([cmd, your_executable_to_check_here])
except: 
    print "No executable"

或者只使用Ned Batchelder的wh.py脚本,这是一个“哪个”跨平台实现:

http://nedbatchelder.com/code/utilities/wh_py.html

答案 3 :(得分:11)

我去找:

import distutils.spawn

def is_tool(name):
  return distutils.spawn.find_executable(name) is not None

答案 4 :(得分:10)

import subprocess
import os

def is_tool(name):
    try:
        devnull = open(os.devnull)
        subprocess.Popen([name], stdout=devnull, stderr=devnull).communicate()
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return True

答案 5 :(得分:5)

我可能会向which wgetwhich curl发出请求,并检查结果是否以您正在使用的程序的名称结尾。 unix的魔力:)

实际上,您需要做的就是检查which的返回代码。所以...使用我们可靠的subprocess模块:

import subprocess

rc = subprocess.call(['which', 'wget'])
if rc == 0:
    print 'wget installed!'
else:
    print 'wget missing in path!'

请注意,我在带有cygwin的windows上测试了这个...如果你想弄清楚如何在纯python中实现which,我建议你在这里查看:http://pypi.python.org/pypi/pycoreutils(哦亲爱的 - 似乎他们不提供which。友好推动的时间?)

更新:在Windows上,您可以使用where代替which获得类似效果。

答案 6 :(得分:4)

我按照以下方式更改@ sorin的答案,原因是它会在不传递程序的绝对路径的情况下检查程序的名称

from subprocess import Popen, PIPE

def check_program_exists(name):
    p = Popen(['/usr/bin/which', name], stdout=PIPE, stderr=PIPE)
    p.communicate()
    return p.returncode == 0

答案 7 :(得分:1)

import os
import subprocess


def is_tool(prog):
    for dir in os.environ['PATH'].split(os.pathsep):
        if os.path.exists(os.path.join(dir, prog)):
            try:
                subprocess.call([os.path.join(dir, prog)],
                                stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT)
            except OSError, e:
                return False
            return True
    return False

答案 8 :(得分:0)

对@ SvenMarnach代码的略微修改,解决了打印到标准输出流的问题。如果您使用subprocess.check_output()函数而不是subprocess.call(),那么您可以处理通常在代码中打印到标准输出的字符串,并仍然捕获异常和退出状态代码。

如果要在终端中禁止标准输出流,请不要打印从check_output返回的标准输出字符串:

import subprocess
import os
try:
    stdout_string = subprocess.check_output(["wget", "--help"], stderr=subprocess.STDOUT)
    # print(stdout_string)
except subprocess.CalledProcessError as cpe:
    print(cpe.returncode)
    print(cpe.output)
except OSError as e:
    if e.errno == os.errno.ENOENT:
        print(e)
    else:
        # Something else went wrong while trying to run `wget`
        print(e)

非零退出状态代码和输出字符串在CalledProcessError中被subprocess.CalledProcessError.returncodesubprocess.CalledProcessError.output引发,因此您可以随意执行任何操作。

如果要将可执行文件的标准输出打印到终端,请打印返回的字符串:

import subprocess
import os
try:
    stdout_string = subprocess.check_output(["wget", "--help"], stderr=subprocess.STDOUT)
    print(stdout_string)
except subprocess.CalledProcessError as cpe:
    print(cpe.returncode)
    print(cpe.output)
except OSError as e:
    if e.errno == os.errno.ENOENT:
        print(e)
    else:
        # Something else went wrong while trying to run `wget`
        print(e)

print()为字符串添加了额外的换行符。如果你想消除它(并将std错误写入std err流而不是std输出流,如上面的print()语句所示),请使用sys.stdout.write(string)sys.stderr.write(string)而不是print() :

import subprocess
import os
import sys
try:
    stdout_string = subprocess.check_output(["bogus"], stderr=subprocess.STDOUT)
    sys.stdout.write(stdout_string)
except subprocess.CalledProcessError as cpe:
    sys.stderr.write(cpe.returncode)
    sys.stderr.write(cpe.output)
except OSError as e:
    if e.errno == os.errno.ENOENT:
        sys.stderr.write(e.strerror)
    else:
        # Something else went wrong while trying to run `wget`
        sys.stderr.write(e.strerror)