当使用Fabric执行远程shell命令时,我能否捕获错误代码?

70

通常情况下,只要run()调用返回非零退出代码,Fabric就会立即退出。但是对于某些调用,这是可以预料的。例如,当PNGOut无法压缩文件时,它返回错误码2。

目前,我只能通过使用shell逻辑(do_something_that_fails || truedo_something_that_fails || do_something_else)来绕过此限制,但我更希望能够将逻辑保持在纯Python中(这是Fabric承诺的)。

是否有一种方法来检查错误代码并对其进行反应,而不是让Fabric恐慌和死亡?我仍然希望其他调用采用默认行为,因此通过修改环境来改变其行为似乎不是一个好选项(据我回忆,您只能使用它来告诉它警告而不是死亡)。


2
在有人标记这个问题为重复之前:这个问题是相关的,但正如我所说,我想要对错误进行_反应_,而不是忽略它们。 - Alan Plum
目前被接受的答案已经过时。自2013年7月以来,有一个环境变量可以让您指定在发生错误时应引发哪个异常(默认值为SystemExit,它不是Exception的子类,这就是为什么它通常会导致程序崩溃的原因)。请参见我的回答:https://dev59.com/Rm445IYBdhLWcg3wZJUn#25293275 - ArtOfWarfare
// 我很好奇 Invoke 会如何处理这个。 - Nathan Basanese
4个回答

97

你可以使用settings上下文管理器和warn_only设置来防止在非零退出码上中止:

from fabric.api import settings

with settings(warn_only=True):
    result = run('pngout old.png new.png')
    if result.return_code == 0: 
        do something
    elif result.return_code == 2: 
        do something else 
    else: #print error to user
        print result
        raise SystemExit()

更新:我的答案已经过时,请参阅下面的评论。


2
你甚至不需要检查return_code,result的值根据任务的成功状态评估为布尔值true或false。http://docs.fabfile.org/en/1.7/api/core/operations.html#fabric.operations.run - Fraser Graham
3
针对超时错误,这种方法不起作用。无论是使用“with settings”还是try/except,甚至是不使用它们,Fabric仍然会完全退出。 - Cerin
-1:这个答案已经过时了 - 自2013年7月以来,已经可以指定在调用错误时调用哪个异常。请参见我的答案:https://dev59.com/Rm445IYBdhLWcg3wZJUn#25293275 - ArtOfWarfare
我修复了Python的缩进,但现在我无法删除我添加的额外文本以使编辑生效。 - Christian Long
3
您可以使用result.succeededresult.failed。请注意,不要直接评估bool(result),因为它使用输出结果,所以与hide("warnings")一起使用时,将无法区分成功与失败。 - rewritten

29

可以的,你只需要改变环境的abort_exception。例如:

from fabric.api import settings

class FabricException(Exception):
    pass

with settings(abort_exception = FabricException):
    try:
        run(<something that might fail>)
    except FabricException:
        <handle the exception>

abort_exception 的文档位于此处


1
虽然这似乎没有提供对命令退出代码的访问。 - Alan Plum
@AlanPlum - 你可以获取异常消息...但是你说得对,我没有看到获取退出代码的方法。 - ArtOfWarfare

4
显然地,操作环境就是答案。 fabric.api.settings 可以作为上下文管理器 (使用 with) 应用于各个语句。 run()local()sudo() 调用的返回值不仅仅是 shell 命令的输出,而且还具有特殊属性 (return_codefailed),允许对错误进行反应。
我想我正在寻找更接近 subprocess.Popen 或 Python 通常的异常处理行为的东西。

2

试一下这个

from fabric.api import run, env
env.warn_only = True # if you want to ignore exceptions and handle them yurself

command = "your command"
x = run(command, capture=True) # run or local or sudo
if(x.stderr != ""):
    error = "On %s: %s" %(command, x.stderr)
    print error
    print x.return_code # which may be 1 or 2
    # do what you want or
    raise Exception(error) #optional
else:
    print "the output of %s is: %s" %(command, x)
    print x.return_code # which is 0

3
我尝试了以上操作,结果出现了以下报错:TypeError: run() got an unexpected keyword argument 'capture'。这是在使用Fabric 1.10.2和Paramiko 1.15.2时发生的。 - dmmfll
capture=True works only for local(command, capture=True) - Kurohige

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接