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

时间:2021-11-25 00:11:20

How do I check if a program exists from a python script?

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

Let's say you want to check if wget or curl are available. We'll assume that they should be in path.

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

It would be the best to see a multiplatform solution but for the moment, Linux is enough.

看到多平台解决方案是最好的,但目前,Linux已经足够了。

Hints:

  • running the command and checking for return code is not always enough as some tools do return non 0 result even when you try --version.
  • 运行命令并检查返回代码并不总是足够的,因为即使您尝试使用--version,某些工具也会返回非0结果。

  • nothing should be visible on screen when checking for the command
  • 检查命令时,屏幕上看不到任何内容

Also, I would appreciate a solution that that is more general, like is_tool(name)

此外,我会感谢一个更通用的解决方案,如is_tool(名称)

10 个解决方案

#1


34  

The easiest way is to try to run the program with the desired parameters, and handle the exception if it doesn't exist:

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

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

This is a common pattern in Python: EAFP

这是Python中的常见模式:EAFP

#2


31  

shutil.which

Let me recommend an option that has not been discussed yet: a Python implementation of which, specifically shutil.which. It was introduced in Python 3.3 and is cross-platform, supporting Linux, Mac, and Windows. It is also available in Python 2.x via whichcraft. You can also just rip the code for which right out of whichcraft here and insert it into your program.

让我推荐一个尚未讨论过的选项:Python的实现,特别是shutil.which。它是在Python 3.3中引入的,是跨平台的,支持Linux,Mac和Windows。它也可以在Python 2.x中通过whichcraft获得。你也可以在这里删除哪些代码,然后将其插入你的程序中。

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

Another option that has already been mentioned is distutils.spawn.find_executable.

已经提到的另一个选项是distutils.spawn.find_executable。

find_executable's docstring is as follows:

find_executable的docstring如下:

Tries to find 'executable' in the directories listed in 'path'

试图在'path'中列出的目录中找到'可执行文件'

So if you pay attention, you'll note that the name of the function is somewhat misleading. Unlike which, find_executable does not actually verify that executable is marked as executable, only that it is on the PATH. So it's entirely possible (however unlikely) that find_executable indicates a program is available when it is not.

因此,如果您注意,您会注意到该功能的名称有些误导。与此不同,find_executable实际上并不验证可执行文件是否被标记为可执行文件,只是它在PATH上。因此,完全可能(但不太可能)find_executable指示程序可用时不可用。

For example, suppose you have a file /usr/bin/wget that is not marked executable. Running wget from the shell will result in the following error: bash: /usr/bin/wget: Permission denied. which('wget') is not None will return False, yet find_executable('wget') is not None will return True. You can probably get away with using either function, but this is just something to be aware of with find_executable.

例如,假设您有一个未标记为可执行文件的文件/ usr / bin / wget。从shell运行wget将导致以下错误:bash:/ usr / bin / wget:权限被拒绝。哪个('wget')不是None将返回False,但find_executable('wget')不是None将返回True。你可以使用任何一种函数,但这只是使用find_executable时需要注意的事情。

def is_tool(name):
    """Check whether `name` is on PATH."""

    from distutils.spawn import find_executable

    return find_executable(name) is not None

#3


15  

You could use a subprocess call to the binary needed with :

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

  • "which" : *nix
  • “哪个”:* nix

  • "where" : Win 2003 and later (Xp has an addon)
  • “where”:Win 2003及更高版本(Xp有一个插件)

to get the executable path (supposing it is in the environment path).

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

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"

or just use Ned Batchelder's wh.py script, that is a "which" cross platform implementation:

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

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

#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


10  

I'd go for:

我会去:

import distutils.spawn

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

#6


4  

I'd change @sorin's answer as follows, the reason is it would check the name of the program without passing the absolute path of the program

我将@ 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


3  

I would probably shell out to which wget or which curl and check that the result ends in the name of the program you are using. The magic of unix :)

我可能会讨论哪个wget或哪个curl并检查结果是否以您正在使用的程序的名称结尾。 unix的魔力:)

Actually, all you need to do is check the return code of which. So... using our trusty subprocess module:

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

import subprocess

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

Note that I tested this on windows with cygwin... If you want to figure out how to implement which in pure python, i suggest you check here: http://pypi.python.org/pypi/pycoreutils (oh dear - it seems they don't supply which. Time for a friendly nudge?)

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

UPDATE: On Windows, you can use where instead of which for a similar effect.

更新:在Windows上,您可以使用where而不是类似的效果。

#8


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

#9


0  

A slight modification to @SvenMarnach's code that addresses the issue of printing to the standard output stream. If you use the subprocess.check_output() function rather than subprocess.call() then you can handle the string that is normally printed to standard out in your code and still catch exceptions and the exit status code.

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

If you want to suppress the standard output stream in the terminal, don’t print the std out string that is returned from check_output:

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

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)

The non-zero exit status code and output string are raised in the CalledProcessError as subprocess.CalledProcessError.returncode and subprocess.CalledProcessError.output so you can do whatever you'd like with them.

在CalledProcessError中将非零退出状态代码和输出字符串作为subprocess.CalledProcessError.returncode和subprocess.CalledProcessError.output引发,以便您可以使用它们执行任何操作。

If you want to print the executable's standard output to the terminal, print the string that is returned:

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

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() adds an extra newline to the string. If you want to eliminate that (and write std error to the std err stream instead of the std out stream as shown with the print() statements above), use sys.stdout.write(string) and sys.stderr.write(string) instead of print():

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)

#10


-1  

For Debian Based systems:

对于基于Debian的系统:

i tested the scripts from above and they wasn't really good. They run the programs and that is annoying because it takes a lot of time and you have to close the programs. I found a solution getting the installed packages with aptitude, and then reading the list.

我测试了上面的脚本,它们并不是很好。他们运行程序,这很烦人,因为它需要很多时间,你必须关闭程序。我找到了一个解决方案,使用aptitude获取已安装的软件包,然后阅读列表。

You can use different kinds of commands to get different kinds of 'installed packages' Exemples: https://askubuntu.com/questions/17823/how-to-list-all-installed-packages

您可以使用不同类型的命令来获取不同类型的“已安装软件包”示例:https://askubuntu.com/questions/17823/how-to-list-all-installed-packages

The two that i found the best was:

我发现最好的两个是:

dpkg --get-selections           # big list
aptitude search '~i!~M' -F      # great list

You can run them in the terminal to test them.

您可以在终端中运行它们来测试它们。


The python function:

python函数:

import os,sys

def check_for_program(program):

    if not os.path.exists("/tmp/program_list"):
        os.system("aptitude search '~i!~M' -F > /tmp/program_list")

    with open('/tmp/program_list') as f:
        for line in f:
            if program in line:
                return True
    return False

#1


34  

The easiest way is to try to run the program with the desired parameters, and handle the exception if it doesn't exist:

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

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

This is a common pattern in Python: EAFP

这是Python中的常见模式:EAFP

#2


31  

shutil.which

Let me recommend an option that has not been discussed yet: a Python implementation of which, specifically shutil.which. It was introduced in Python 3.3 and is cross-platform, supporting Linux, Mac, and Windows. It is also available in Python 2.x via whichcraft. You can also just rip the code for which right out of whichcraft here and insert it into your program.

让我推荐一个尚未讨论过的选项:Python的实现,特别是shutil.which。它是在Python 3.3中引入的,是跨平台的,支持Linux,Mac和Windows。它也可以在Python 2.x中通过whichcraft获得。你也可以在这里删除哪些代码,然后将其插入你的程序中。

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

Another option that has already been mentioned is distutils.spawn.find_executable.

已经提到的另一个选项是distutils.spawn.find_executable。

find_executable's docstring is as follows:

find_executable的docstring如下:

Tries to find 'executable' in the directories listed in 'path'

试图在'path'中列出的目录中找到'可执行文件'

So if you pay attention, you'll note that the name of the function is somewhat misleading. Unlike which, find_executable does not actually verify that executable is marked as executable, only that it is on the PATH. So it's entirely possible (however unlikely) that find_executable indicates a program is available when it is not.

因此,如果您注意,您会注意到该功能的名称有些误导。与此不同,find_executable实际上并不验证可执行文件是否被标记为可执行文件,只是它在PATH上。因此,完全可能(但不太可能)find_executable指示程序可用时不可用。

For example, suppose you have a file /usr/bin/wget that is not marked executable. Running wget from the shell will result in the following error: bash: /usr/bin/wget: Permission denied. which('wget') is not None will return False, yet find_executable('wget') is not None will return True. You can probably get away with using either function, but this is just something to be aware of with find_executable.

例如,假设您有一个未标记为可执行文件的文件/ usr / bin / wget。从shell运行wget将导致以下错误:bash:/ usr / bin / wget:权限被拒绝。哪个('wget')不是None将返回False,但find_executable('wget')不是None将返回True。你可以使用任何一种函数,但这只是使用find_executable时需要注意的事情。

def is_tool(name):
    """Check whether `name` is on PATH."""

    from distutils.spawn import find_executable

    return find_executable(name) is not None

#3


15  

You could use a subprocess call to the binary needed with :

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

  • "which" : *nix
  • “哪个”:* nix

  • "where" : Win 2003 and later (Xp has an addon)
  • “where”:Win 2003及更高版本(Xp有一个插件)

to get the executable path (supposing it is in the environment path).

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

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"

or just use Ned Batchelder's wh.py script, that is a "which" cross platform implementation:

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

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

#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


10  

I'd go for:

我会去:

import distutils.spawn

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

#6


4  

I'd change @sorin's answer as follows, the reason is it would check the name of the program without passing the absolute path of the program

我将@ 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


3  

I would probably shell out to which wget or which curl and check that the result ends in the name of the program you are using. The magic of unix :)

我可能会讨论哪个wget或哪个curl并检查结果是否以您正在使用的程序的名称结尾。 unix的魔力:)

Actually, all you need to do is check the return code of which. So... using our trusty subprocess module:

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

import subprocess

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

Note that I tested this on windows with cygwin... If you want to figure out how to implement which in pure python, i suggest you check here: http://pypi.python.org/pypi/pycoreutils (oh dear - it seems they don't supply which. Time for a friendly nudge?)

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

UPDATE: On Windows, you can use where instead of which for a similar effect.

更新:在Windows上,您可以使用where而不是类似的效果。

#8


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

#9


0  

A slight modification to @SvenMarnach's code that addresses the issue of printing to the standard output stream. If you use the subprocess.check_output() function rather than subprocess.call() then you can handle the string that is normally printed to standard out in your code and still catch exceptions and the exit status code.

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

If you want to suppress the standard output stream in the terminal, don’t print the std out string that is returned from check_output:

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

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)

The non-zero exit status code and output string are raised in the CalledProcessError as subprocess.CalledProcessError.returncode and subprocess.CalledProcessError.output so you can do whatever you'd like with them.

在CalledProcessError中将非零退出状态代码和输出字符串作为subprocess.CalledProcessError.returncode和subprocess.CalledProcessError.output引发,以便您可以使用它们执行任何操作。

If you want to print the executable's standard output to the terminal, print the string that is returned:

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

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() adds an extra newline to the string. If you want to eliminate that (and write std error to the std err stream instead of the std out stream as shown with the print() statements above), use sys.stdout.write(string) and sys.stderr.write(string) instead of print():

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)

#10


-1  

For Debian Based systems:

对于基于Debian的系统:

i tested the scripts from above and they wasn't really good. They run the programs and that is annoying because it takes a lot of time and you have to close the programs. I found a solution getting the installed packages with aptitude, and then reading the list.

我测试了上面的脚本,它们并不是很好。他们运行程序,这很烦人,因为它需要很多时间,你必须关闭程序。我找到了一个解决方案,使用aptitude获取已安装的软件包,然后阅读列表。

You can use different kinds of commands to get different kinds of 'installed packages' Exemples: https://askubuntu.com/questions/17823/how-to-list-all-installed-packages

您可以使用不同类型的命令来获取不同类型的“已安装软件包”示例:https://askubuntu.com/questions/17823/how-to-list-all-installed-packages

The two that i found the best was:

我发现最好的两个是:

dpkg --get-selections           # big list
aptitude search '~i!~M' -F      # great list

You can run them in the terminal to test them.

您可以在终端中运行它们来测试它们。


The python function:

python函数:

import os,sys

def check_for_program(program):

    if not os.path.exists("/tmp/program_list"):
        os.system("aptitude search '~i!~M' -F > /tmp/program_list")

    with open('/tmp/program_list') as f:
        for line in f:
            if program in line:
                return True
    return False