Bash 脚本:如何确保脚本在使用“或”(||) 条件调用的函数中出现任何错误时退出?
Posted
技术标签:
【中文标题】Bash 脚本:如何确保脚本在使用“或”(||) 条件调用的函数中出现任何错误时退出?【英文标题】:Bash scripting: How to ensure script exits on any error in function called with an "or" (||) condition? 【发布时间】:2019-08-10 23:55:17 【问题描述】:这是一个示例脚本:
#!/bin/bash
set -euo pipefail
function_test ()
echo "Everything still ok."
thisdoesnotexist
echo "It continues running..."
function_test || echo "Error occured in function_test."; exit 1;
我希望此脚本在“thisdoesnotexist”上退出,因为 set -e 已激活。错误消息“function_test 中发生错误”。应该出现,或者至少应该退出脚本。相反,脚本继续运行:
$ ./testscript.sh
Everything still ok.
./testscript.sh: Zeile 6: thisdoesnotexist: Kommando nicht gefunden.
It continues running...
根据set
的手册,我认为这是因为我在“或”(||) 上下文中使用该函数:
立即退出 [...] 除非失败的命令是 until 或 while 循环,if 语句的一部分,&& 或 || 的一部分 列表,[...]
在脚本中处理此问题的最佳方法是什么?我删除了“||”并使用了这样的错误陷阱:
#!/bin/bash
set -Eeuo pipefail
errorhandler ()
echo "Errorhandler called. Exiting."
exit 1
trap "errorhandler" ERR
function_test ()
echo "Everything still ok."
thisdoesnotexist
echo "It continues running..."
function_test
哪个有效:
$ ./testscript.sh
Everything still ok.
./testscript.sh: Zeile 13: thisdoesnotexist: Kommando nicht gefunden.
Errorhandler called. Exiting.
在这种情况下,虽然似乎不可能输出用户友好的消息(例如,其中包含脚本中发生错误的步骤)。为此,我至少必须将函数名称传递给错误陷阱。我试过了,但没有找到可行的解决方案。
你有更好的建议吗?
【问题讨论】:
【参考方案1】:function_test || echo "Error occured in function_test."; exit 1;
由于函数返回状态,OR 永远不会发生。该函数的最后一个 echo 语句导致返回状态为 0,因为它已成功运行。
如果您在不成功的命令上添加非零返回,那么它将导致 OR 语句正常运行。
function_test ()
echo "Everything still ok."
thisdoesnotexist || return 1;
echo "It continues running..."
【讨论】:
【参考方案2】:不是很消耗,但在某些情况下更可取。导出标志和您的函数,并在子外壳中运行它。处理 bash 错误值。
#!/bin/bash
set -euo pipefail
function_test ()
echo "Everything still ok."
thisdoesnotexist
echo "It continues running..."
export -f function_test
export SHELLOPTS
bash -c function_test || echo "Error occured in function_test."; exit 1;
【讨论】:
【参考方案3】:如果你想在出错的情况下做一些事情并且你知道可能会出错,那么:
function_test ()
echo "Everything still ok."
thisdoesnotexist ||
# handle thisdoesnotexist failure
Echo "thisdoesnotexist failed" >&2
exit 1
echo "It continues running..."
if ! thisdoesnotexisteither; then
# Handle fail for thisdoesnotexisteither
Echo "thisdoesnotexisteither failed" >&2
exit 1
fi
现在为了测试 Bash 中的错误处理,您可以使用这个智能错误功能:
#!/usr/bin/env bash
# Generate an error
# @Params
# $1: Numeric error return code
# $2[@]: Messages
# @Output
# &1: Generic success message
# &2: Generic or passed error messages
# @Return
# $?: Intended return code
erroring()
local rc=1
if [ "$#" -gt 0 ]; then
rc="$1"
shift
if printf '%d' "$rc" >/dev/null 2>&1; then
# rc is an integer
if [ "$rc" -gt 0 ]; then
printf $"Intended failure with code: %d\\n" "$rc" >&2
if [ "$#" -gt 0 ]; then
# There are supplied messages to print"
printf $"%d messages:\\n" "$#" >&2
printf '%q\n' "$@" >&2
fi
else
echo $"Intended success"
fi
else
printf $"Invalid non-numeric return code parameter: %q\\n" "$rc" >&2
rc=7
fi
else
erroring "$rc"
fi
return "$rc"
【讨论】:
最后一个printf $'Invalid
- 这是printf $"Invalid
?递归调用erroring
有什么意义? if [ "$#" -gt 0 ]; then rc=$1; else rc=1; fi
不是更简单吗?
这是 erroring
函数失败的糖,因为它传递了一个非数字返回码。就像打电话给erroring "Error message"
而不是打电话给erroring 1 "Error message"
以上是关于Bash 脚本:如何确保脚本在使用“或”(||) 条件调用的函数中出现任何错误时退出?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用“sh”或“bash”命令的情况下运行 shell 脚本?