在 Bash 中模拟 do-while 循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16489809/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 23:42:05  来源:igfitidea点击:

Emulating a do-while loop in Bash

bashloopsdo-while

提问by Alex

What is the best way to emulate a do-while loop in Bash?

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

I could check for the condition before entering the whileloop, and then continue re-checking the condition in the loop, but that's duplicated code. Is there a cleaner way?

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

Pseudo code of my script:

我的脚本的伪代码:

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

This doesn't perform check_if_file_presentif launched after the $cutofftime, and a do-while would.

check_if_file_present如果在该$cutoff时间之后启动,则不会执行此操作,而 do-while 会执行。

回答by jm666

Two simple solutions:

两个简单的解决方案:

  1. Execute your code once before the while loop

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

    while : ; do
        actions
        [[ current_time <= $cutoff ]] || break
    done
    
  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
    

回答by Paused until further notice.

Place the body of your loop after the whileand before the test. The actual body of the whileloop should be a no-op.

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

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

Instead of the colon, you can use continueif you find that more readable. You can also insert a command that will only run betweeniterations (not before first or after last), such as echo "Retrying in five seconds"; sleep 5. Or print delimiters between values:

continue如果您发现冒号更具可读性,则可以使用它来代替冒号。您还可以插入一个仅迭代之间运行的命令(不在第一个或最后一个之前),例如echo "Retrying in five seconds"; sleep 5. 或打印值之间的分隔符:

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

I changed the test to use double parentheses since you appear to be comparing integers. Inside double square brackets, comparison operators such as <=are lexical and will give the wrong result when comparing 2 and 10, for example. Those operators don't work inside single square brackets.

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

回答by Chetabahana

We can emulate a do-while loop in Bash with while [[condition]]; do true; donelike this:

我们可以while [[condition]]; do true; done像这样在 Bash 中模拟 do-while 循环:

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

For an example. Here is my implementation on getting ssh connectionin bash script:

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

#!/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

It will give the output in sequence as below:

它将按顺序给出输出,如下所示:

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' ([email protected]: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"