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.



Source link