[bash] Emulating a do-while loop in Bash

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

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

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_present if launched after the $cutoff time, and a do-while would.

This question is related to bash loops do-while

The answer is


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

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

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

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.


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

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

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

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

This implementation:

  • Has no code duplication
  • Doesn't require extra functions()
  • Doesn't depend on the return value of code in the "while" section of the loop:
do=true
while $do || conditions; do
  do=false
  # your code ...
done

It works with a read loop, too, skipping the first read:

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

  # your code ...
  echo $foo
done

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to loops

How to increment a letter N times per iteration and store in an array? Angular 2 Cannot find control with unspecified name attribute on formArrays What is the difference between i = i + 1 and i += 1 in a 'for' loop? Prime numbers between 1 to 100 in C Programming Language Python Loop: List Index Out of Range JavaScript: Difference between .forEach() and .map() Why does using from __future__ import print_function breaks Python2-style print? Creating an array from a text file in Bash Iterate through dictionary values? C# Wait until condition is true

Examples related to do-while

How to find sum of several integers input by user using do/while, While statement or For statement WHILE LOOP with IF STATEMENT MYSQL Emulating a do-while loop in Bash JAVA - using FOR, WHILE and DO WHILE loops to sum 1 through 100 Are "while(true)" loops so bad? Do while loop in SQL Server 2008 do-while loop in R 'do...while' vs. 'while' How to emulate a do-while loop in Python?