Making your script responsive
Tips and Tricks
By now, you know which flow control schemes are available in Bash, how they differ from each other, and the corresponding syntax. To make the most of those techniques, however, you need some other tricks.
Sooner or later, for example, you will need to let a script decide on the fly not just what to do and how many times to do it, but also at which speed it should do it. In these cases, all you need is the sleep
command, with an argument that is recalculated every time. Here is how to make a for
loop wait one second more at every iteration:
INTERVAL=0 for ((I=0;I<5;I++)) do #some commands let "INTERVAL++" sleep $INTERVAL done
Another handy trick is efficiently extracting, inside a loop, the components of an element that has spaces in it. You already know that adding quotes in the right places is the only way to make this loop process the two actual customers, namely "Jane Eyre" and "John Smith," instead of four non-existing ones (Jane, Eyre, John and Smith):
for CUSTOMER in "Jane Eyre" "John Smith" do #something done
But what if, for every customer, you need to process the name and surname separately? One solution would be an additional, inner loop splitting each customer record into its parts. Often, however, you may do without that extra loop thanks to the set
command, which assigns each substring of a list to a positional variable:
for CUSTOMER in "Jane Eyre" "John Smith" do set -- $CUSTOMER echo "Name: $1 Surname: $2" done
This will print lines like "Name: Jane Surname: Eyre".
Interrupting Loops
As useful as Bash control flow structures are, they would be pretty useless if they did not include ways to stop themselves. You can tell a script to interrupt the execution of a branch of code with the continue
and break
keywords. continue
interrupts the current iteration of the loop it is in, skipping all the remaining commands in that particular loop cycle. On the other hand, break
terminates the whole loop where it is located (see Listing 3).
Listing 3
The break Keyword
Both keywords accept an optional numeric parameter, which says upon how many levels of nested loops they act. Without arguments, break
terminates only the innermost loop in which it is embedded, but break N
breaks out of N
loop levels. Similarly, continue N
terminates all remaining iterations at its loop level and continues with the next iteration of the loop N
levels above.
The most effective way I know, to understand these Bash features is to copy the little script shown in Listing 4, and then run it several times, each time commenting a different break
statement or adding a numeric value to it.
Listing 4
Practice break Script
A Practical Example
I'll close this Bash tutorial installment with an example of flow control in real-world scripts. Listing 5 is a stripped down version of a script I actually put together a while ago to implement custom quota controls on a shared server. The high-level algorithm, shown in Figure 2, works as follows:
Listing 5
quoteguardian.sh
- It continuously checks the disk usage.
- If the disk is almost full, just declare an emergency and start deleting the biggest files, whoever they belong to, until usage falls below a threshold.
If the disk is not full, but the situation is critical, remove one file per user, until usage returns below another threshold. For each user, delete oldest files first.
1 Otherwise, continue monitoring disk usage.
Lines 3 to 10 define and initialize all the variables needed by the script. In this example, I have three users (dave
, john
, and mark
) keeping their files in their own subfolders of the $H
directory. Please note that a complete version of the script should not use a hardwired list of users as in line 9; instead, configure users through the $USERS
array and modify the array whenever users are added or removed from the server!
The echo
lines throughout the script report the disk usage and which files were deleted in each moment. They are useful to understand how the script actually works when you try it in a terminal. In a complete script, however, you would want to replace or complete the echo
lines with commands that, for example, send a warning email to the system administrator!
Another repeated line of the script is the one used to calculate $DISKUSAGE
. That line takes the total output of the df
command and prints only its fifth column, but removes the percentage sign. Try it alone, one piece at a time, to see how each step works.
Line 12 starts the main loop. To make that loop go on forever, I put "1"
as condition in the while
statement, because any non-null value is always "true" by definition in Bash. While running, the script can be in one of three states corresponding to the thresholds mentioned above:
EMERGENCY
: Disk usage is 95 percent or higher (THRESHOLD_MAX
)CRITICAL
: Disk usage is between 85 and 95 percentWATCHING
: Disk usage is not higher than 85 percent (THRESHOLD_MED
)
The default condition in line 64 guarantees that the script always acquires a known state, even when it begins and neither $DISKSTATUS
nor $DISKUSAGE
are defined yet.
The script stay in EMERGENCY
status (lines 16 to 30), the script stays there as long as $DISKUSAGE
is greater than or equal to $THRESHOLD_MAX
. Whenever it enters that phase, the script first saves inside $BIGFILES
a list of all the files in $H
, sorted by size from biggest to smallest (line 17). It then reads that list one line at a time, deleting the $BIGGESTFILE
(lines 21 to 24) until $DISKUSAGE
remains above $THRESHOLD_MAX
. Otherwise, it sets $DISKSTATUS
to CRITICAL
and breaks the loop (lines 26 and 27).
In the "CRITICAL"
status (lines 32 to 52) the script still deletes files until $DISKUSAGE
falls below $THRESHOLD_MED
(lines 34 and 51), in order to make room on the disk. When that condition is not true anymore, $DISKSTATUS
becomes "WATCHING"
(line 53). However, file deletion happens at a much slower pace (line 50) and with a completely different criterion.
The code continuously loops over all users (lines 36 to 49). At every iteration, that loop creates a list of all the files belonging to the current user and saves the oldest one in the $OLDESTFILE
variable (lines 38 to 40). Then, if $DISKUSAGE
is still higher than $THRESHOLD_MED
, that file is deleted; otherwise the loop is broken (lines 42 to 48).
The "WATCHING"
state in lines 55 to 63 does nothing but check every five seconds whether $DISKUSAGE
is below the $THRESHOLD_MED
value or not. If not, it immediately goes back to "EMERGENCY"
.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Linux Servers Targeted by Akira Ransomware
A group of bad actors who have already extorted $42 million have their sights set on the Linux platform.
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs