Back in about 1987, I started working for a very small company running out of offices on London’s South Bank -hence their name, SouthBank Systems PLC. They wrote specialist, database-based applications for local councils and their contractors to manage how their parks, street trees and other amenity values should be maintained.
I learnt so much in that job -that Bowling Greens are about the most expensive piece of grass you can ever install, per square meter, for example. Or that, if you make the mistake of writing your code this way, it is easy to generate “random inspection lists” that send an inspector first to one site, then a second on the other side of the borough, then back to a third… which was adjacent to the first! Who knew that what they really needed was a random selection of sites that were then sorted into an ordered, walkable path. Well, we did eventually: but it took us a while before the penny dropped!
One of the first-ever training sessions I ever gave took place in a greenhouse in Aldershot, where the contractors were bemused by the two minutes of frenetic activity they’d seen me do before turning to them to speak. They wanted to know what I’d done, because it looked interesting. It took a moment for me to work out what they were intrigued by, but yeah: they wanted to know how to switch a computer on and what happens when you do. I learnt how to read audience expectations that day!
Anyway, one of the little features of our software we were quite proud of, and which the clients loved, was Jaws. He was simply a shark fin that paced up and down the screen, letting you know that stuff was happening in the background. These days we call them progress bars and don’t think much about them, but to the kind of people I was working with back then, the “personality” of the progress bar was important.
I’d therefore like to present you with my 25-year tribute to Jaws, The SouthBank Systems progress bar, as implemented in Bash, as follows:
function jaws() {
i=1
char=">"
pos=4
while true
do
i=$((i+1))
if [ $(($i%60)) -eq 0 ]; then
if [ "$char" = ">" ]; then
char="<"
else
char=">"
fi
fi
if [ "$char" = ">" ]; then
pos=$((pos+1))
if [ "$pos" -gt 60 ]; then
pos=60
fi
else
pos=$((pos-1))
if [ "$pos" -lt 5]; then
pos=5
fi
fi
tput cup 18 5; echo "............................................................";
tput cup 18 $(($pos)); echo -n $char;tput cup 20 5
sleep 0.2
done
}
The variable “i” forever increments. But we pick a point when its value can be tested. In this case we check whether i modulus 60 is zero. (that is, can “i” be devided by 60 without leaving any remainder). If it is, then we use that to trigger a change in the progress bar character from “>” to “<”. Additionally, if we are left with “>” as our character, then we know to keep on incrementing the position where that character should be displayed. If we acquire a “<”. then the position counter will be decreased.
So you stick that function at the top of your bash script somewhere, and then it comes time to use it. Here’s the simplest case:
jaws & jawsp=$! sleep 40 kill $jawsp &>/dev/null
The “thing” this script is doing is simply to sleep for 40 seconds, but it could be doing any meaningful work. The point is that before the work starts, you invoke the jaws function -with an ampersand character (&) to make it run in a new, background session. We assign the process ID of that new session to a jawsp variable. When our sleep/work has finished, we can kill that process, which will stop the shark fins parading up and down the screen.
Eighties tribute bands are seldom worth the price of admission and it is similarly likely that you will consider Jaws a not very exciting addition to your set of Bash scripting skills. You may indeed be bemused that there was a highly professional set of clients and staff who thought Jaws was one of our most valuable bits of IP (shocking, but true, I fear). But even if it’s as welcome as a Mama Mia reunion ‘do’ at the Hammersmith Palais on a wet Wednesday night, I’m going to let you watch the video anyway because, for me, he brings back happy memories when my database skills extended to re-building DataFlex indexes and showing gardeners how to turn on a PC. Happy times!
Coming soon to a Gladstone shell script near you shortly, of course…
And cheers to Chris Megan, who wrote the original, all those moons ago.


line 23 seems to be gobbled up: instead of
if [ "$pos" -lt 5]‘ then
it should rather read
if [ "$pos" -lt 5 ]; then
And I’m sorry that I don’t know how properly format code in a comment. It’s good reading you again (just stumbled over your blog today searching for conky).
Cheers
Holger
Absolutely right. My finger hit an apostrophe when it was reaching for the semi-colon. I’ll get that corrected. Happily, the correct syntax made it into the Gladstone shell script.
Howzit You Smooth Blogging Dude Dowunder,
I am deeply honoured by those kind comments.
I am also pleased that your prose continues, although, way over my head nowadays. How about some non-geeky output to balance it up…
Here’s a little something I threw together this year for Burning Man…
http://www.youtube.com/watch?v=u00OF3ilNUs
You welcome in Cape Town, anytime, dear Howard…
And for some really useless use, it can be run in older ksh (that doesn’t have < 1 second sleep) by simply removing the parens in the first line, and substituting the sleep with some slowdown like
while [ $j -lt 50 ]
do
j=`expr $j + 1`
done
Cheers Joel. I hadn’t realised he wouldn’t work in ksh. I’m not even going to think about csh.