如果函数内部的条件失败,则跳过 bash while 循环
Posted
技术标签:
【中文标题】如果函数内部的条件失败,则跳过 bash while 循环【英文标题】:Skip bash while loop if function inside fails a condition 【发布时间】:2018-11-16 20:39:44 【问题描述】:我有一个 while 循环,它逐行读取文件并将该行传递给循环内的多个函数或嵌套函数。如果其中一个函数发现有问题,我希望 while 循环跳过该迭代并转到下一个迭代。
我确实进行了很多搜索并尝试了不同的方法,但使用 'continue 跳过 while 循环是唯一的解决方案,但它似乎没有帮助。我不确定在哪里或如何寻找这样的东西。是否有解决此问题的解决方案或不同的方法?感谢您的帮助。
function2()
"if some condition that uses $test_name fails, skip the while loop"
function3()
do something
main_function ()
do something to $test_name
function2 $test_name
function3 $test_name
while true read -r line; do
if [[ ! "$line" =~ ^# && ! -z "$line" ]]; then
test_name=$line
main_function $test_name
fi
done < $OS_LIST
【问题讨论】:
确保您的函数都返回有效的成功 (0) 或失败(非零)代码。让 main_function 每个都以func $arg || return 1
或类似的方式执行,这样它就不会在一个失败后继续运行测试。然后调用 main 为main_function $arg || continue
。
我猜你回答了我问安德烈的问题,非常感谢你的清晰解释,我会的。
我不知道为什么这个问题被否决了,有人可以帮帮我吗?
如果您希望我提交一个完整的示例,请告诉我。
不知道反对票。如果我不得不猜测,我会说阅读 this 解释为什么你应该提供简短但明确的证据来证明你所做的研究。
【参考方案1】:
首先,编写函数,使它们在失败时返回非零状态,如果成功则返回零(实际上,作为一般的良好做法,无论如何您都应该这样做)。像这样的:
function2()
if some condition that uses $test_name fails; then
echo "test condition failed in function2" >&2 # Error messages should be sent to stderr
return 1
fi
# Code here will only be executed if the test succeeded
do_something || return 1
# Code here will only be executed if the test AND do_something both succeeded
do_something_optional # No error check here means it'll continue even if this fails
do_something_else ||
echo "do_something_else failed in function2" >&2
return 1
return 0 # This is actually optional. By default it'll return the status
# of the last command in the function, which must've succeeded
请注意,您可以根据情况在此处混合样式(if
vs ||
vs 其他)。一般来说,使用最清晰的样式,因为你最大的敌人是对代码在做什么感到困惑。
然后,在主函数中,您可以检查每个子函数的退出状态,如果其中任何一个失败,则提前返回:
main_function ()
do something to "$test_name" || return 1 # BTW, you should double-quote variable references
function2 "$test_name" || return 2 # optional: you can use different statuses for different problems
function3 "$test_name" || return 1
如果您需要跳过主循环的结尾,您可以使用continue
:
while true read -r line; do
if [[ ! "$line" =~ ^# && ! -z "$line" ]]; then
test_name=$line
main_function "$test_name" || continue
echo "Finished processing: $line" >&2 # Non-error status messages also go to stderr
fi
done < "$OS_LIST"
【讨论】:
感谢@Gordon Davisson 的精彩解释。在@Paul Hodges 的帮助下,我刚刚在我的代码中实现了相同的功能。感谢您的详细解释,它一定会帮助其他人。【参考方案2】:我的看法-
$: cat failout
#! /bin/env bash
OS_LIST=os_list
func1()
if [[ -z "$1" ]]
then echo "ERROR - Empty string!"
return 1
fi
func2()
grep -q foo <<< "$1" || echo "ERROR - no 'foo'!"; return 1;
func3() echo "all good here";
mainfunc()
func1 "$1" || return 1
func2 "$1" || return 1
func3 "$1" || return 1
while read -r line
do echo "before:[$line]"
mainfunc "$line" || echo test failed; continue;
echo all tests passed.
done < <( grep -Ev '^[[:space:]]*(#.*)*$' $OS_LIST )
请注意,循环在读取之前使用 grep 消除 cmets 和空行。
输入文件,os_list,带有行号
$: vi os_list
1
2
3
4 # shan't
5
6 foo bar other stuff
7
8 just foo
9
10 footed...
11
12 bar, without any required string!
13
14 more foo
15
16
为了记录,这些空行中有些确实有空格,有些则没有。 结果:
$: failout
before:[foo bar other stuff]
all good here
all tests passed.
before:[just foo]
all good here
all tests passed.
before:[footed...]
all good here
all tests passed.
before:[bar, without any required string!]
ERROR - no 'foo'!
test failed
before:[more foo]
all good here
all tests passed.
希望对您有所帮助。它当然可以更好。 欢迎提问。
【讨论】:
我刚刚提交了一个答案,其中涵盖了一些我认为还没有很好涵盖的内容......我看到你已经打败了我。哦,好吧,投个赞成票。【参考方案3】:好吧,如果测试失败,在函数 2 中:
return 1
在主函数中:
if [[ $? -eq 0 ]]; then
function3 $test_name
else
return
fi
希望对你有帮助
【讨论】:
非常感谢@Andre Gelinas。我还有一个问题,如果我在functions3之后有更多的功能,如果我想对func3做同样的事情,我是否需要在去function4之前添加你的if条件等等? 相同,return n 使您能够发送错误代码。 0 是默认值,通常表示一切正常。但是通过像这样设置特定的错误代码,您甚至可以对每个功能进行更精细的处理并做出相应的反应。就像如果函数 2 不起作用并返回假设错误代码 2,请不要执行函数 3,而是执行函数 6,而不是通过示例跳过。以上是关于如果函数内部的条件失败,则跳过 bash while 循环的主要内容,如果未能解决你的问题,请参考以下文章
oracle 查询条件中判断两个字段相等时 一个字段为空则跳过