Linux bash tips: Many ways to loop using bash
The bash shell provides a superb functionality when it comes to writing scripts. This includes many ways to loop through a pile of data so that you can get a lot done with one running of a script. Whether you’re looping through a large group of numeric values, days of the week, usernames, words, files, or something else entirely, bash has an option that can make it easy for you.
for, while, and until loops
The first thing you need to know about looping in bash is that there are several basic commands to use. The while loop will loop as long as some particular condition holds true. The until loop will loop until some condition becomes true, and the for loop will run through a series of values regardless of their origin.
For example, using while, you can loop while a number is smaller than 100, loop through the remaining days in the month as shown in the script below (in which we grab the current day using the date command and the final day from the last string in the output of the cal command) or loop through something altogether different.
#/bin/bash # day of month day=`date | awk '{print $3'}` # number of days in month numdays=`cal | tail -2 | head -1 | awk '{print $NF}'` while [ $day -le $numdays ] do echo $day ((day++)) done
When we run this script, we should see something like this:
$ remaining_days 27 28 29 30
This next script loops until a coworker logs in. As long as the count of the user’s logins is zero (i.e., he or she is not logged in), we display “waiting” and then wait another 60 seconds. Once the user is logged in, the while loop is exited and, within the next 60 seconds, a message is displayed confirming the user’s login presence.
#!/bin/bash echo -n "user to wait for> " read user while [ `who | grep $user | wc -l` == 0 ] do echo waiting sleep 60 done echo $user is online
The until loop version of the script is very similar.
#!/bin/bash echo -n "user to wait for> " read user until [ `who | grep $user | wc -l` -gt 0 ] do echo waiting sleep 60 done
In for loops, we run through a series of values, but there are many commands that you can use to generate those values.
The while and until commands are further explained in How to repeat a Linux command until it succeeds
Looping through letters and numbers
You can loop through a string of numbers or letters by specifying a range of values in the {start..stop} format as in the examples below. Note that you can start with any value you want. You don’t have to start with an “a” or a “0”.
$ for letter in {a..f}; do echo $letter; done a b c d e f
In this next example, we start with 5, not 1, and avoid the carriage returns with an echo -n command.
$ for number in {5..11}; do echo -n "$number "; done 5 6 7 8 9 10 11 $
You can even reverse the order of the numbers or letters if you want. Here are a couple examples:
$ for letter in {z..x}; do echo $letter; done z y x
$ for number in {11..7} > do > echo $number > done 11 10 9 8 7
Looping forever
The easiest way to loop forever is to use a “while true” loop. The loop will only stop running if you kill it – for example, with a ^C. If it’s included in a script that is running in the background, you can use a kill command (e.g., kill 654321) to terminate the script.
$ while true > do > echo Hello > sleep 60 > done Hello Hello ^C
More information on looping forever is available at How to loop forever in bash on Linux.
Escaping loops with break and continue
The break and continue commands allow you to jump out of a loop entirely (break) or restart at the top of the loop (continue), skipping over any commands between the continue command and the end of the loop.
The break and continue commands are explained in more detail at Using break and continue to exit loops.
The fold command can be used to split a file or string into same-size pieces. The default length is 80 characters. In this example, we break the string into 11-character chunks with the -c11 (11 characters) option.
$ fold -c11 trythis This file h as a few ri diculously long charac ter strings . Oh, well.
When you use the fold command in a for loop, however, you need to remember that any resultant character string that contains a blank will result in one or more extra loops because for breaks on each blank-separated string.
$ for line in `fold -c10 trythis` > do > echo -n "$line" > echo -n ":" > echo $line | wc -c > done This:5 file:5 has:4 a:2 few:4 ridiculous:11 ly:3 long:5 ch:3 aracter:8 st:3 rings.:7 Oh,:4 well.:6
More on the fold command can be found at Using fold to make text more readable and Using the fold command to drive loops.
Looping word-by-word
To loop through a list of words using a for loop, you can run a command like the one below. Notice that the apostrophe needs to be escaped so as not to be interpreted as the beginning of a string.
$ for word in all's well that ends well; do echo $word; done all's well that ends well
If you want to loop through the months of the year, you can use a command like this:
$ for month in `locale mon | sed 's/;/ /g'`; do echo $month; done January February March April May June July August September October November December
The command above uses the locale command to get a list of months and sed to break the semi-colon separated line into individual months.
Wrap-Up
Looping in scripts and on the command line on Linux is clearly one of the best techniques for getting a lot done in a short amount of time and with the least amount of effort, especially if you turn your loops into scripts that you can run as often as needed without having to think through all the details each time.
Copyright © 2022 IDG Communications, Inc.