Python中,子,()调用,check_call和返回码找到,如果一个命令存在(Python, s

2019-08-05 04:15发布

我已经想通了如何使用()调用让我的python脚本来运行命令:

import subprocess

mycommandline = ['lumberjack', '-sleep all night', '-work all day']
subprocess.call(mycommandline)

这工作,但有一个问题,如果有什么用户没有伐木工人在他们的命令路径? 它会工作,如果伐木工人被放在同一目录python脚本,但如何脚本知道应该找樵夫? 我想如果有一个命令未找到错误,则樵夫不会命令路径,该脚本可以揣摩它的目录是什么,寻找伐木工人有最后警告用户复制成樵夫的一个如果它没有任何一个发现这两个地方。 如何找出错误消息是什么? 我读了check_call()可以返回一个错误信息,并有一个什么返回码属性。 我找不到关于如何使用check_call()和返回代码的例子,有什么消息会或者如果消息是我会怎么告诉命令未找到。

上午我甚至会对此正确的方法是什么?

Answer 1:

一个简单的代码片段:

try:
    subprocess.check_call(['executable'])
except subprocess.CalledProcessError:
    pass # handle errors in the called executable
except OSError:
    pass # executable not found


Answer 2:

subprocess将引发异常, OSError ,当找不到一个命令。

当命令被找到,并且subprocess运行命令你,结果代码从命令返回。 的标准是,代码0表示成功,以及任何故障是一些非零的错误代码(其变化而变化;检查正在运行的特定命令的文档)。

所以,如果你抓到OSError您可以处理不存在的命令,如果你检查结果的代码,你可以找出命令是否成功与否。

关于伟大的事情subprocess是你可以把它收集所有从文本stdoutstderr ,然后你就可以将其丢弃或退回,或记录,或你喜欢显示它。 我经常使用丢弃命令所有输出,除非该命令将失败在这种情况下,从文本的包装stderr输出。

我同意,你不应该要求用户复制周围的可执行文件。 方案应该是在中列出的目录PATH变量; 如果一个程序丢失,应当安装,或者如果它被安装在一个目录没有在PATH用户应更新PATH以包括目录。

请注意,你有尝试的选项subprocess与各种硬编码路径多次可执行文件:

import os
import subprocess as sp

def _run_cmd(s_cmd, tup_args):
    lst_cmd = [s_cmd]
    lst_cmd.extend(tup_args)
    result = sp.call(lst_cmd)
    return result

def run_lumberjack(*tup_args):
    try:
        # try to run from /usr/local/bin
        return _run_cmd("/usr/local/bin/lumberjack", tup_args)
    except OSError:
        pass

    try:
        # try to run from /opt/forest/bin
        return _run_cmd("/opt/forest/bin/lumberjack", tup_args)
    except OSError:
        pass

    try:
        # try to run from "bin" directory in user's home directory
        home = os.getenv("HOME", ".")
        s_cmd = home + "/bin/lumberjack"
        return _run_cmd(s_cmd, tup_args)
    except OSError:
        pass

    # Python 3.x syntax for raising an exception
    # for Python 2.x, use:  raise OSError, "could not find lumberjack in the standard places"
    raise OSError("could not find lumberjack in the standard places")

run_lumberjack("-j")

编辑:思考它一点点之后,我决定彻底重写上面。 这是干净多了,只是传的位置列表,并有一个循环尝试替代的位置,直到一个工作。 但我并没有想建立字符串为用户的主目录,如果没有必要,所以我只是做是合法的把一个可调用到替代品的清单。 如果您对此有任何疑问,就问我。

import os
import subprocess as sp

def try_alternatives(cmd, locations, args):
    """
    Try to run a command that might be in any one of multiple locations.

    Takes a single string argument for the command to run, a sequence
    of locations, and a sequence of arguments to the command.  Tries
    to run the command in each location, in order, until the command
    is found (does not raise OSError on the attempt).
    """
    # build a list to pass to subprocess
    lst_cmd = [None]  # dummy arg to reserve position 0 in the list
    lst_cmd.extend(args)  # arguments come after position 0

    for path in locations:
        # It's legal to put a callable in the list of locations.
        # When this happens, we should call it and use its return
        # value for the path.  It should always return a string.
        if callable(path):
            path = path()

        # put full pathname of cmd into position 0 of list    
        lst_cmd[0] = os.path.join(path, cmd)
        try:
            return sp.call(lst_cmd)
        except OSError:
            pass
    raise OSError('command "{}" not found in locations list'.format(cmd))

def _home_bin():
    home = os.getenv("HOME", ".")
    return os.path.join(home, "bin")

def run_lumberjack(*args):
    locations = [
        "/usr/local/bin",
        "/opt/forest/bin",
        _home_bin, # specify callable that returns user's home directory
    ]
    return try_alternatives("lumberjack", locations, args)

run_lumberjack("-j")


Answer 3:

哇,这是快! 我结合Theodros Zelleke的简单的例子,steveha的使用功能有关OSERROR和Lattyware的有关移动文件注释abarnert评论:

import os, sys, subprocess

def nameandpath():
    try:
        subprocess.call([os.getcwd() + '/lumberjack']) 
        # change the word lumberjack on the line above to get an error
    except OSError:
        print('\nCould not find lumberjack, please reinstall.\n')
        # if you're using python 2.x, change the () to spaces on the line above

try:
    subprocess.call(['lumberjack'])
    # change the word lumberjack on the line above to get an error
except OSError:
    nameandpath()

我测试了它在Mac OS-X(6.8 /雪豹),Debian的(挤压)和Windows(7)。 它似乎工作,我想它在所有三个操作系统的方式。 我尝试使用check_call和CalledProcessError但无论我做什么,我似乎每次都得到一个错误,我不能让脚本来处理错误。 为了测试脚本,我从“樵夫”到“deadparrot”改了名字,因为我和我的脚本的目录有樵夫。

你看到这个剧本的任何问题它的编写方式?



文章来源: Python, subprocess, call(), check_call and returncode to find if a command exists