如何让 RETURN 陷入 bash 保留 return 代码?
How to make RETURN trap in bash preserve the return code?
下面是我正在编写的脚本的简化方案。程序必须以不同的方式获取参数,因此对几个功能进行了精细划分。
问题是来自更深层函数的 return 值的链式加载在陷阱处中断,要检查结果以显示消息。
#! /usr/bin/env bash
check_a_param() {
[ "" = 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() {
[ "" = 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’.
它应该如何工作:
↗ 3 → 3→ trap →3 ↗ || ask_for_params ↘
check_a_param >>> check_params >>> [ ! -v MANUAL ] ↓
↘ 0 → 0→ trap →0 ↘ && ____________ do_the_job
这个想法是,如果检查失败,它的 return 代码也会强制 check_params()
到 return,这反过来会触发 || ask_for_params
条件在 setup()
。但是陷阱returns 0:
↗ 3 → 3→ trap →0
check_a_param >>> check_params >>> [ ! -v MANUAL ] &&… >>> do_the_job
↘ 0 → 0→ trap →0
如果您尝试 运行 原样的脚本,您应该会看到
Bad, bad… Dropping to manual setup.
check_params() returned with 0. Not running manual setup.
这意味着错误的结果触发了陷阱(!)但是设置它的母函数没有传递结果。
为了尝试设置破解,我已经尝试过
- 将 retval 设置为
return_trap()
中的全局变量 declare -g retval=$?
并在设置陷阱的行中使用它的值。变量已设置([ -v retval ]
returns 成功),但是……没有值。好笑。
- 好吧,让我们把
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
没有任何区别。
当现代软件衰落时,是时候求助于旧的写入文件的好方法了。让我们用 return_trap()
中的 retval=$?; echo $retval >/tmp/t
将 retval 打印到 /tmp/t 并用
读回
trap "return_trap; trap - RETURN; return $(</tmp/t)" RETURN
现在我们终于可以看到最后一个从文件中读取数字的return指令实际上是returns 3。但是check_params()
仍然是returns 0 !
++ 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 就是原始结果。原来的一个,不是什么return_trap()
returns。我试图增加结果,但仍然得到 3。
您可能还会问“为什么您需要如此频繁地解除陷阱?”。这是为了避免另一个错误,该错误导致陷阱每次都触发,即使从另一个函数调用 check_params()
时也是如此。 RETURN 上的陷阱是本地事物,它们不会被其他函数继承,除非在它们上面明确设置了调试或跟踪标志,但看起来它们在 运行 之间保持陷阱设置。或者 bash 为他们设置陷阱。仅当从特定函数调用 check_params() 时才应设置此陷阱,但如果未取消设置陷阱,则每次 check_a_param()
return 的值大于零与 FUNCNAME[1]
中的内容无关。
这里我放弃了,因为我现在看到的唯一出口就是在check_params()
中的每个|| return $?
之前实现对调用函数的检查。但是真的丑到我眼睛疼
我只能补充一点,$?
在设置陷阱的行中 将始终 return 0。 因此,例如,如果您声明local
变量 retval
in return_trap()
,并放入这样的代码来检查它
trap "return_trap; [ -v retval ]; echo $?; trap - RETURN; return $retval" RETURN
不管是否实际设置了retval
,它都会打印0,但是如果你使用
trap "return_trap; [ -v retval ] && echo set || echo unset; trap - RETURN; return $retval" RETURN
它会打印‘unset’。
GNU bash,版本 4.3.39(1)-release (x86_64-pc-linux-gnu)
够有趣,
trap "return_trap; trap - RETURN" RETURN
简单有效。
[ ! -v MANUAL ] && {
check_params; retval2=$?
[ $retval2 -eq 0 ] \
&& echo "check_params() returned with 0. Not running manual setup." \
|| false
}|| ask_for_params
这是踪迹。
+ 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
命令的行中的结果 。 Bash 为您包办一切。
下面是我正在编写的脚本的简化方案。程序必须以不同的方式获取参数,因此对几个功能进行了精细划分。
问题是来自更深层函数的 return 值的链式加载在陷阱处中断,要检查结果以显示消息。
#! /usr/bin/env bash
check_a_param() {
[ "" = 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() {
[ "" = 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’.
它应该如何工作:
↗ 3 → 3→ trap →3 ↗ || ask_for_params ↘
check_a_param >>> check_params >>> [ ! -v MANUAL ] ↓
↘ 0 → 0→ trap →0 ↘ && ____________ do_the_job
这个想法是,如果检查失败,它的 return 代码也会强制 check_params()
到 return,这反过来会触发 || ask_for_params
条件在 setup()
。但是陷阱returns 0:
↗ 3 → 3→ trap →0
check_a_param >>> check_params >>> [ ! -v MANUAL ] &&… >>> do_the_job
↘ 0 → 0→ trap →0
如果您尝试 运行 原样的脚本,您应该会看到
Bad, bad… Dropping to manual setup.
check_params() returned with 0. Not running manual setup.
这意味着错误的结果触发了陷阱(!)但是设置它的母函数没有传递结果。
为了尝试设置破解,我已经尝试过
- 将 retval 设置为
return_trap()
中的全局变量declare -g retval=$?
并在设置陷阱的行中使用它的值。变量已设置([ -v retval ]
returns 成功),但是……没有值。好笑。 - 好吧,让我们把
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
没有任何区别。 当现代软件衰落时,是时候求助于旧的写入文件的好方法了。让我们用
读回return_trap()
中的retval=$?; echo $retval >/tmp/t
将 retval 打印到 /tmp/t 并用trap "return_trap; trap - RETURN; return $(</tmp/t)" RETURN
现在我们终于可以看到最后一个从文件中读取数字的return指令实际上是returns 3。但是check_params()
仍然是returns 0 !
++ 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 就是原始结果。原来的一个,不是什么return_trap()
returns。我试图增加结果,但仍然得到 3。
您可能还会问“为什么您需要如此频繁地解除陷阱?”。这是为了避免另一个错误,该错误导致陷阱每次都触发,即使从另一个函数调用 check_params()
时也是如此。 RETURN 上的陷阱是本地事物,它们不会被其他函数继承,除非在它们上面明确设置了调试或跟踪标志,但看起来它们在 运行 之间保持陷阱设置。或者 bash 为他们设置陷阱。仅当从特定函数调用 check_params() 时才应设置此陷阱,但如果未取消设置陷阱,则每次 check_a_param()
return 的值大于零与 FUNCNAME[1]
中的内容无关。
这里我放弃了,因为我现在看到的唯一出口就是在check_params()
中的每个|| return $?
之前实现对调用函数的检查。但是真的丑到我眼睛疼
我只能补充一点,$?
在设置陷阱的行中 将始终 return 0。 因此,例如,如果您声明local
变量 retval
in return_trap()
,并放入这样的代码来检查它
trap "return_trap; [ -v retval ]; echo $?; trap - RETURN; return $retval" RETURN
不管是否实际设置了retval
,它都会打印0,但是如果你使用
trap "return_trap; [ -v retval ] && echo set || echo unset; trap - RETURN; return $retval" RETURN
它会打印‘unset’。
GNU bash,版本 4.3.39(1)-release (x86_64-pc-linux-gnu)
够有趣,
trap "return_trap; trap - RETURN" RETURN
简单有效。
[ ! -v MANUAL ] && {
check_params; retval2=$?
[ $retval2 -eq 0 ] \
&& echo "check_params() returned with 0. Not running manual setup." \
|| false
}|| ask_for_params
这是踪迹。
+ 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
命令的行中的结果 。 Bash 为您包办一切。