如果函数内部的条件失败,则跳过 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 查询条件中判断两个字段相等时 一个字段为空则跳过

ORACLE查询条件为空,则跳过该条件。

Qt程序调试之Q_ASSERT断言(条件为真则跳过,否则直接异常+崩溃)

如果已安装,则跳过 MSI

如果 wget 中已经存在文件,则跳过下载?

如果对象为空,则跳过 for 循环