【问题标题】:Emulating a do-while loop in Bash在 Bash 中模拟 do-while 循环
【发布时间】:2013-05-05 14:00:34
【问题描述】:

在 Bash 中模拟 do-while 循环的最佳方法是什么?

我可以在进入while 循环之前检查条件,然后继续重新检查循环中的条件,但这是重复的代码。有没有更清洁的方法?

我的脚本的伪代码:

while [ current_time <= $cutoff ]; do
    check_if_file_present
    #do other stuff
done

如果在$cutoff 时间之后启动,这不会执行check_if_file_present,而do-while 会。

【问题讨论】:

  • 您在寻找until 开关吗?
  • @MichaelGardner until 还将在执行循环体之前评估条件
  • 啊,我明白了,我误解了你的困惑。

标签: bash loops do-while


【解决方案1】:

两个简单的解决方案:

  1. 在while循环之前执行一次你的代码

    actions() {
       check_if_file_present
       # Do other stuff
    }
    
    actions #1st execution
    while [ current_time <= $cutoff ]; do
       actions # Loop execution
    done
    
  2. 或者:

    while : ; do
        actions
        [[ current_time <= $cutoff ]] || break
    done
    

【讨论】:

  • : 是内置的,相当于内置的true。他们都“什么都不做”。
  • @loxaxs 在例如zsh 但不在 Bash 中。 true 是一个实际的程序,而 : 是内置的。前者简单地以0 退出(和false1),后者完全什么都不做。您可以通过which true查看。
  • @Fleshgrinder : 仍然可以在 Bash 中代替 true 使用。试试while :; do echo 1; done
  • 从来没有说过什么不同,只是 true 不是 Bash 的内置功能。这是一个通常在/bin中找到的程序。
  • type true 在 bash 中(一直回到 bash 3.2)返回 true is a shell builtin/bin/true确实是一个程序;关于 true 的不正确之处在于 true 不是内置函数。 (tl;dr: true 是一个内置的 bash 和一个程序)
【解决方案2】:

将循环体放在while 之后和测试之前。 while 循环的实际主体应该是空操作。

while 
    check_if_file_present
    #do other stuff
    (( current_time <= cutoff ))
do
    :
done

如果您发现冒号更易读,您可以使用continue,而不是冒号。您还可以插入仅在 between 迭代(不是在第一次或最后一次之后)运行的命令,例如 echo "Retrying in five seconds"; sleep 5。或者打印值之间的分隔符:

i=1; while printf '%d' "$((i++))"; (( i <= 4)); do printf ','; done; printf '\n'

我将测试更改为使用双括号,因为您似乎在比较整数。在双方括号内,比较运算符如&lt;= 是词法运算,例如在比较 2 和 10 时会给出错误的结果。这些运算符在单方括号内不起作用。

【讨论】:

  • 是否相当于单行while { check_if_file_present; ((current_time&lt;=cutoff)); }; do :; done? IE。是while 条件中的命令有效地用分号而不是例如&amp;&amp;,并按{}分组?
  • @Ruslan:花括号是不必要的。您不应该使用&amp;&amp;|| 将任何内容链接到双括号内的测试,因为这实际上使它们成为控制while 的测试的一部分。除非您在命令行上使用此构造,否则我不会将其作为单行符(特别是在脚本中),因为其意图不可读。
  • 是的,我不打算将它用作单行:只是为了阐明测试中的命令是如何连接的。我担心第一个返回非零的命令可能会使整个条件为假。
  • @ruslan:不,这是最后一个返回值。 while false; false; false; true; do echo here; break; done 输出“这里”
  • @thatotherguy:between 功能非常酷!您还可以使用它在字符串中插入分隔符。谢谢!
【解决方案3】:

这个实现:

  • 没有代码重复
  • 不需要额外的函数()
  • 不依赖于循环“while”部分代码的返回值:
do=true
while $do || conditions; do
  do=false
  # your code ...
done

它也适用于读取循环,跳过第一次读取:

do=true
while $do || read foo; do
  do=false

  # your code ...
  echo $foo
done

【讨论】:

    【解决方案4】:

    我们可以在 Bash 中使用 while [[condition]]; do true; done 模拟一个 do-while 循环,如下所示:

    while [[ current_time <= $cutoff ]]
        check_if_file_present
        #do other stuff
    do true; done
    

    举个例子。这是我在 bash 脚本中获取 ssh connection 的实现:

    #!/bin/bash
    while [[ $STATUS != 0 ]]
        ssh-add -l &>/dev/null; STATUS="$?"
        if [[ $STATUS == 127 ]]; then echo "ssh not instaled" && exit 0;
        elif [[ $STATUS == 2 ]]; then echo "running ssh-agent.." && eval `ssh-agent` > /dev/null;
        elif [[ $STATUS == 1 ]]; then echo "get session identity.." && expect $HOME/agent &> /dev/null;
        else ssh-add -l && git submodule update --init --recursive --remote --merge && return 0; fi
    do true; done
    

    它会按如下顺序给出输出:

    Step #0 - "gcloud": intalling expect..
    Step #0 - "gcloud": running ssh-agent..
    Step #0 - "gcloud": get session identity..
    Step #0 - "gcloud": 4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /builder/home/.ssh/id_rsa (RSA)
    Step #0 - "gcloud": Submodule '.google/cloud/compute/home/chetabahana/.docker/compose' (git@github.com:chetabahana/compose) registered for path '.google/cloud/compute/home/chetabahana/.docker/compose'
    Step #0 - "gcloud": Cloning into '/workspace/.io/.google/cloud/compute/home/chetabahana/.docker/compose'...
    Step #0 - "gcloud": Warning: Permanently added the RSA host key for IP address 'XXX.XX.XXX.XXX' to the list of known hosts.
    Step #0 - "gcloud": Submodule path '.google/cloud/compute/home/chetabahana/.docker/compose': checked out '24a28a7a306a671bbc430aa27b83c09cc5f1c62d'
    Finished Step #0 - "gcloud"
    

    【讨论】:

    猜你喜欢
    • 2010-10-19
    • 2022-09-22
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    相关资源
    最近更新 更多