BASH Programming

Bash Until Loops

There are several types of loops that can be used in bash scripts. For loops, while loops and until loops.

Conceptually the for loop should be used to loop through a series of items such as loop through each item in an array or each file in a directory, etc. The while loop should be used as long as a certain condition is true, such as the a counter is less than a maximum value or the ping time to a server is lower than a threshold or forever if you loop while TRUE or while 1.

The until loop is similar to the while loop but with reverse logic. Instead of looping while a condition is true you are assuming the condition is false and looping until it becomes true. They are reverse of each other in logical expression. Choosing the correct loop between a while loop and until loop allows your program to be more readable and understandable by others or yourself when you come back to the code sometime later.

Some typical examples or reasons to use a until loop could be, loop until the user enters ‘exit’; loop until the data generated is greater than the requested data volume, or until a number of files that match your search are found.

The basic syntax of UNTIL loop looks like this:

until [ CONDITION ]; do
  LINES OF CODE
  MORE LINES OF CODE
done

Now lets take some examples. The first example will multiple factor of two until reaching a size threshold of 1000:

#!/bin/bash
NUM=1
until [ "$NUM" -gt 1000 ]; do
  echo $NUM
  let NUM=NUM*2
done

The second example will continue to ping a URL until the response time is greater than 100 milliseconds:

#!/bin/bash
MILLISECONDS=0

# we will ping until it becomes slower than 1000 milliseconds
until [ $MILLISECONDS -gt 1000 ]
do
  # run the ping and extract the line that has the ping time, which ends in time=XXXX ms  
  OUTPUT=`ping -c 1 google.com | grep time | awk -F= '{ print $NF }'`
  echo "Ping time: $OUTPUT"

  # extract number of milliseocnds from string as integer
  MILLISECONDS=`echo $OUTPUT | awk '{ print $1 }' | awk -F. '{ print $1 }' `
  echo "Number of ms = $MILLISECONDS"

  sleep 1
done

echo "ping time exceeded 1000 milliseconds"

The third example will take a file and will combine the file with itself until it reaches 1 kilobyte in size:

#!/bin/bash
FILENAME=`basename "$0"`
echo $FILENAME
TMP_FILE="./tmp1"
TARGET_FILE="./target"
cat $FILENAME > $TARGET_FILE
FILESIZE=0

# increase file size until 1KB
until [ $FILESIZE -gt 1024 ]
do
  # add this file to target file content
  cp $TARGET_FILE $TMP_FILE
  cat $TMP_FILE >> $TARGET_FILE

  FILESIZE=`du $TARGET_FILE | awk '{ print $1 }'`
  echo "Filesize: $FILESIZE"

  sleep 1
done

echo "new filesize reached target of 1KB"

The fourth example will ask the user for input of their name until they type exit to quit the program:

#!/bin/bash
RESPONSE="FOO"

# increase file size until 1KB
until [ "$RESPONSE" = "exit" ]
do
  echo -n "Enter your name or 'exit' to quit this program: "
  read RESPONSE
  if [ "$RESPONSE" != "exit" ]; then
    echo "Hello $RESPONSE"
  fi
done

echo "Thank you for playing this game"

CONCLUSION

The key point is to use UNTIL loop to make your code more clear when the condition is expected to be always false and then you want to stop your looping action when the condition becomes true.  In other words, continue looping UNTIL some point in time.  With this perspective I hope your bash scripts can be more clear and you have learned something with this article. Thank you.

About the author

Linux Wolfman

Linux Wolfman is interested in Operating Systems, File Systems, Databases and Analytics and always watching for new technologies and trends. Reach me by tweeting to @linuxhint and ask for the Wolfman.