首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使bash中的返回陷阱保留返回代码?

如何使bash中的返回陷阱保留返回代码?
EN

Stack Overflow用户
提问于 2016-04-06 05:50:36
回答 1查看 4.1K关注 0票数 8

下面是我正在编写的脚本的简化方案。程序必须以不同的方式接受参数,因此可以很好地划分几个函数。

问题是,来自更深的函数的返回值的链式加载会在陷阱上中断,结果将被检查以显示一条消息。

代码语言:javascript
复制
#! /usr/bin/env bash

check_a_param() {
    [ "$1" = return_ok ] && return 0 || return 3
}

check_params() {
    # This trap should catch negative results from the functions
    #   performing actual checks, like check_a_param() below.
    return_trap() {
        local retval=$?
        [ $retval -ne 0 ] && echo 'Bad, bad… Dropping to manual setup.'
        return $retval
    }
    # check_params can be called from different functions, not only
    #   setup(). But the other functions don’t care about the return value
    #   of check_params().
    [ "${FUNCNAME[1]}" = setup ] \
        && trap "return_trap; got_retval=$?; trap - RETURN; return $got_retval;" RETURN
    check_a_param 'return_bad' || return $?
    # …
    # Here we check another parameters in the same way.
    # …
    echo 'Provided parameters are valid.'
    return 0  # To be sure.
}

ask_for_params() {
    echo 'User sets params manually step by step.'
}

setup() {
    [ "$1" = force_manual ] && local MANUAL=t
    # If gathered parameters do not pass check_params()
    #   the script shall resort to asking user for entering them.
    [ ! -v MANUAL ] && {
        check_params \
            && echo "check_params() returned with 0. Not running manual setup."
            || false
    }|| ask_for_params
    # do_the_job
}

setup "$@"  # Either empty or ‘force_manual’.

它应如何运作:

代码语言:javascript
复制
              ↗ 3 → 3→ trap →3                     ↗ || ask_for_params ↘
 check_a_param >>> check_params >>> [ ! -v MANUAL ]                     ↓
              ↘ 0 → 0→ trap →0                     ↘ && ____________ do_the_job

这样做的想法是,如果检查失败,其返回代码也会迫使check_params()返回,这反过来将触发setup()中的|| ask_for_params条件。但是陷阱返回0:

代码语言:javascript
复制
              ↗ 3 → 3→ trap →0
 check_a_param >>> check_params >>> [ ! -v MANUAL ] &&… >>> do_the_job
              ↘ 0 → 0→ trap →0

如果您试图按原样运行脚本,您应该看到

代码语言:javascript
复制
Bad, bad… Dropping to manual setup.
check_params() returned with 0. Not running manual setup.

这意味着坏结果触发了陷阱(!)但是设置它的母函数没有传递结果。

我已经试过了

  • 将retval设置为return_trap()中的全局变量return_trap(),并在设置陷阱的行中使用它的值。变量被设置([ -v retval ]成功返回),但是…没有价值。有趣的。
  • 好的,让我们将retval=Eeh放到check_params()中,在return_trap()之外,然后将其设置为$?作为通常的参数。不,函数中的retval不为全局变量设置值,而是保留“Eeh”。不,没有local指令。默认情况下,应该将其视为全局的。如果您将test=1放在check_params()test=3中的check_a_param()中,然后在setup()末尾用echo $test打印它,那么您应该会看到3,至少我看到了。正如预期的那样,declare -g在这里没有任何不同。
  • 也许这就是功能的范围?不,也不是这样。移动return_trap()declare -g retval=Eeh没有任何区别。
  • 当现代软件意味着失败的时候,是时候求助于对一个文件进行良好的旧式书写了。让我们用retval=$?; echo $retval >/tmp/treturn_trap()中打印到/tmp/t,然后用 trap "return_trap; trap - RETURN; return $(</tmp/t)" RETURN

现在我们终于可以看到,最后一个返回指令读取文件中的数字,实际上返回3。但是check_params()仍然返回0!

代码语言:javascript
复制
++ trap - RETURN
++ return 3
+ retval2=0
+ echo 'check_params() returned with 0. Not running manual setup.'
check_params() returned with 0. Not running manual setup.

如果trap命令的参数严格地是一个函数名,它将返回原始结果。原始版本,而不是return_trap()返回的内容。我试着增加结果,结果仍然是3。你也可能会问:‘你为什么要这么多地解除陷阱?’这是为了避免另一个bug,这会导致每次都触发陷阱,即使是从另一个函数调用check_params()时也是如此。陷阱在返回时是本地的,除非在它们上显式设置了调试或跟踪标志,否则它们不会被其他函数继承,但是看起来它们在运行过程中会保留设置在它们上的陷阱。或者巴什给他们留了陷阱。只有当从特定函数调用check_params()时,才应该设置这个陷阱,但如果未取消设置,则每次check_a_param()返回大于零的值时(与FUNCNAME[1]中的值无关),它都会继续被触发。

这里我放弃了,因为我现在看到的唯一出口是在|| return $?中的每个check_params()之前实现对调用函数的检查。但太丑了我的眼睛都疼了。

我可能只添加一下,在设置陷阱的行中,将始终返回0.,因此,例如,如果您在return_trap()中声明了一个local变量retval,并将这些代码用于检查它。

代码语言:javascript
复制
trap "return_trap; [ -v retval ]; echo $?; trap - RETURN; return $retval" RETURN

不管是否实际设置了retval,它都会打印0,但如果您使用

代码语言:javascript
复制
trap "return_trap; [ -v retval ] && echo set || echo unset; trap - RETURN; return $retval" RETURN

它会打印“unset”。

GNU,版本4.3.39(1)-release (x86_64-pc-linux-gnu)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-06 05:56:34

够有趣的了,

代码语言:javascript
复制
trap "return_trap; trap - RETURN" RETURN

只是起作用了。

代码语言:javascript
复制
[ ! -v MANUAL ] && {
    check_params; retval2=$?
    [ $retval2 -eq 0 ] \
        && echo "check_params() returned with 0. Not running manual setup." \
        || false
}|| ask_for_params

这是痕迹。

代码语言:javascript
复制
+ check_a_parameter return_bad
+ '[' return_bad = return_ok ']'
+ return 3
+ return 3
++ return_trap
++ local retval=3
++ echo 3
++ '[' 3 -ne 0 ']'
++ echo 'Bad, bad… Dropping to manual setup.'
Bad, bad… Dropping to manual setup.
++ return 3
++ trap - RETURN
+ retval2=3
+ '[' 3 -eq 0 ']'
+ false
+ ask_for_params
+ echo 'User sets params manually step by step.'
User sets params manually step by step.

因此,答案很简单:不试图覆盖传递给trap命令的行中的结果。巴什帮你处理一切。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36442572

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档