Creating a Bash Spinner
Do you know what this sequence of characters "/-\|/-\|" is for? A text based spinner. Still confused, read on.
You've probably seen some long running console program that shows a spinner while it runs. A spinner being the aforementioned sequence of characters output one after the other at the same place on the screen with a pause between each character. The code in this article creates a spinner which runs in a separate process. By doing this the spinner spins at a constant rate and doesn't pause when your script pauses. It also eliminates the need to sprinkle spinner output messages throughout your program.
In addition the spinner reads from a log file created by the main process and displays the last line from the log file next to the spinner. When the log file goes away the spinner exits.
This is the script for the main process, called runner.sh:
#!/bin/bash
logfile=/tmp/mylog
echo >$logfile
trap "rm -f $logfile" EXIT
# Output message to log file.
function log_msg()
{
echo "$*" >>$logfile
}
# Start spinner
sh spinner.sh &
# Perform really long task.
i=0
log_msg "Starting a really long job"
while [[ $i -lt 100 ]]
do
sleep 1
let i+=5
log_msg "$i% complete"
done
sleep 1
echo
The function at the top is to output a message to the log file. The log file is initialized to an empty file at the top of the program and the output function appends to it.
Before entering its main loop, the main process starts the spinner in the background. After that it just pauses a bit, outputs a status message and then repeats till it's 100% complete.
The spinner process follows:
#!/bin/bash
logfile=/tmp/mylog
logsize=0
spinpause=0.10
linelen=0
# Output last line from log file.
function lastout()
{
local line=$(tail -n 1 $logfile 2>/dev/null)
if [[ "$line" ]]; then
echo -n " $line"
# Erase any extra from last line.
local len
let len=$linelen-${#line}
while [[ $len -gt 0 ]]
do
echo -n " "
let len--
done
linelen=${#line}
fi
}
# Output a spin character.
function spinout()
{
local spinchar="$1"
local sz
local ll
if [[ -f $logfile ]]; then
echo -n -e "\r$spinchar"
sleep $spinpause
# Check for new message.
sz=$(stat --printf '%s' $logfile 2>/dev/null)
if [[ $sz -gt $logsize ]]; then
lastout
logsize=$sz
fi
fi
}
if [[ -f $logfile ]]; then
logsize=$(stat --printf '%s' $logfile 2>/dev/null)
if [[ $logsize -gt 0 ]]; then
echo -n " "
lastout
fi
while [[ -f $logfile ]]
do
spinout "/"
spinout "-"
spinout "\\"
spinout "|"
spinout "/"
spinout "-"
spinout "\\"
spinout "|"
done
echo
fi
The spinner contains two functions. The first function outputs the last line from the log file. Since the log file line is always placed on the same screen line it's possible that the new log line is shorter than the last log line. So, after outputting the new line the function outputs spaces up to the length of the previous log line so that it is completely erased.
The second function outputs a spinner character and pauses for the inter-character pause time. It precedes the spinner character with a carriage return so that everything remains on the same line. After outputting the spinner character it checks to see if the log file has grown in size since the last time it output a line. If it has, it then outputs a new line.
The main loop of the spinner outputs each of the spinner characters, one after the other.
Watch the attached video the see it run.
| Attachment | Size |
|---|---|
| spinner.mp4 | 1.05 MB |
| spinner.ogv | 1.55 MB |
Mitch Frazier is an Associate Editor for Linux Journal.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- seo services in india
2 hours 35 min ago - For KDE install kio-mtp
2 hours 35 min ago - Evernote is much more...
4 hours 35 min ago - Reply to comment | Linux Journal
13 hours 21 min ago - Dynamic DNS
13 hours 55 min ago - Reply to comment | Linux Journal
14 hours 53 min ago - Reply to comment | Linux Journal
15 hours 44 min ago - Not free anymore
19 hours 45 min ago - Great
23 hours 33 min ago - Reply to comment | Linux Journal
23 hours 41 min ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



Comments
redundancy
is there a reason why you print two identical sets of the characters instead of just one (
)?
Just Goofy I Guess
Nope, it's not necessary. I guess I just starting rotating the spinner image in my brain to count the positions and never noticed when the characters actually repeated.
Mitch Frazier is an Associate Editor for Linux Journal.
Here's my 'spin' on this tip :)
Here's one I wrote a while ago. It basically puts the twirly characters in a string and cuts the "next" character in the animation sequence. The term "twirly" is coined by my then-3yr-old ;)
I can't get the "code" HTML tag to properly format this code block. If someone at LJ can make it pretty like Mitch's, that would be most appreciated ;).
#!/bin/bash shopt -s xpg_echo twirl() { tc="`echo $twirlstr | cut -c$j`" col=$1 [[ "${tc}" == "\\" ]] && echo "${esc}[${col}G\\${tc}\c" [[ "${tc}" == "\\" ]] || echo "${esc}[${col}G${tc}\c" [[ $j -eq 5 ]] || ((j++)) [[ j -eq 5 ]] && j=1 } twirlstr="-\|/" declare -i j=1 esc="\\033" echo "This is a twirly example:" for (( i=1 ; i < 100 ; i++ )) do echo "${esc}[0GDoing stuff...............................\c" #" # Print the next twirly character at colume 45 twirl 45 # lines of code to "do stuff" done echo "\n"Of course, this is just a sample...the "for" loop would realistically be something more like a "while" or some such thing. This scriplet uses ANSI VTxxx escape sequences to place the cursor.
Preeeeeeeeeeee
That would be <pre>...</pre>, I guess we have droopy set to filter out <code> tags.
Fixed.
Thanks for the twirly!
Mitch Frazier is an Associate Editor for Linux Journal.
Let me re-phrase that
Apparently <code> tags aren't filtered out, they just don't seem to work correctly. Oh webmaster...
Mitch Frazier is an Associate Editor for Linux Journal.
Another Correction
I wasn't able to get the 2 scripts to work until I changed the call in runner.sh
From:
sh spinner.sh &
To:
bash spinner.sh &
Default shell
Your default shell must not be bash. Probably better to make spinner.sh executable and execute it via
Just make sure that the copy of spinner.sh that you have doesn't have the typo referred to in the comment below.
Mitch Frazier is an Associate Editor for Linux Journal.
Minor typo
FYI, just a small typo...
The second code section starts with:
#!/bin/basn
Great article though! I look forward to using this in my code!
Fixed
Thanks.
Mitch Frazier is an Associate Editor for Linux Journal.