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

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

脚本的伪代码:

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

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


当前回答

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

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

如果您觉得continue更具可读性,可以使用continue代替冒号。您还可以插入一个只在迭代之间运行的命令(不是在第一次迭代之前或最后一次迭代之后),例如回显“重试5秒”;睡眠5。或在值之间打印分隔符:

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

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

其他回答

这个实现:

没有代码重复 不需要额外函数() 不依赖于循环"while"部分代码的返回值:

do=true
while $do || conditions; do
  do=false
  # your code ...
done

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

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

  # your code ...
  echo $foo
done

我们可以用while [[condition]]来模拟Bash中的do-while循环;做真正的;这样做:

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

举个例子。这是我在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

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

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"

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

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

如果您觉得continue更具可读性,可以使用continue代替冒号。您还可以插入一个只在迭代之间运行的命令(不是在第一次迭代之前或最后一次迭代之后),例如回显“重试5秒”;睡眠5。或在值之间打印分隔符:

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

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

两个简单的解决方案:

在while循环之前执行一次代码 行动(){ check_if_file_present #做其他事情 } 行动#第一次执行 While [current_time <= $cutoff];做 actions #循环执行 完成 或者: 同时:;做 行动 [[current_time <= $cutoff]] || break . [[current_time <= $cutoff] 完成