Bash is more powerful than you think

Perl, Python, and Ruby modules can ease development for large projects, but Bash is simpler and better for many tasks

yellow tech background with html code
Credit: Shutterstock

Last week I talked a bit about how best to protect against the vagaries of human error, happenstance, and Murphy’s Law in regard to remote devices. Most of that includes trying to anticipate every possible circumstance that may occur and provide some kind of protection against them, such as remote-controlled power distribution devices that can automatically power-cycle a device if network connectivity is lost or scripts that run on remote devices that can make sure that some form of remote access, such Dropbear SSH, is running and available.

It’s the latter — scripts — that I’ll expand on this week. We live in an age where we have very many options for writing interpreted code. Perl, Python, and Ruby are commonly used for CLI control and management scripts, and they offer a plethora of modules that can make all kinds of functions easier to develop. Automating SSH or Telnet sessions, working with SNMP, file manipulation, accessing remote systems — all of those can be done through Perl or Python modules, Ruby gems, or what have you. But that ease of development comes with a price, and that price is portability and ease of installation.

We also live in an age where there is a very quixotic split among *nix folks. There are those who see the simplicity and portability of Bash/Zsh/Tcsh shell scripts and those who eschew shell scripting as something of a forgotten age, to be replaced as soon as possible with something more “modern”— written in Python, perhaps, or Ruby or Go. These tend to be the same people who can’t get enough of Zsh as a shell, oddly enough, but the thought of writing a shell script is anathema. I’m not quite sure how that happens, but it’s definitely a prevalent sentiment.

The fact of the matter is there’s an awful lot to like about shell scripting. The raw simplicity and portability aspects are significant, certainly, but it’s also a readable language to those familiar with the shell — they don’t have to be programmers to understand the workings of a shell script.

For instance, let’s look at a situation where I want to write a utility that connects to another system via SSH and runs commands to check various elements. I could write this in Python with Paramiko, say, or Twisted Conch or even subprocess.Popen. These will require modules to be installed and configured, or in the case of subprocess.Popen, I’m calling system binaries anyway. I would be dozens of lines into a Python script to get started, or I could write this in Bash:

#!/bin/bash
echo -n "Checking /etc/resolv.conf..."
ssh -i id_dsa root@$1 'grep "nameserver 8.8.8.8" \
/etc/resolv.conf' > /dev/null 2>&1
if [ $? -gt 0 ]; then
    echo "Error encountered."
else
    echo "OK"
fi

Assuming I have my pubkey installed on the remote server (which would be necessary in all other other methods as well) I have written a shell script to check a file on a remote system, with error handling. If you want to get fancier and have a lot of items to check, you could use SSH multiplexing and a function:

#!/bin/bash
usage="Usage: $0 <ip address>"
if [ ! $1 ]; then
    echo $usage
    exit
fi
ip=$1
checkresult() {
    if [ $? -gt 0 ]; then
        echo "Problem encountered, aborting."
        ssh -O exit -S /tmp/ssh_mux_%h_%p_%r root@$ip >/dev/null 2>&1
        exit
    else
        echo "Completed."
    fi
}
# Start an ssh control session in the background with no command.
ssh -S /tmp/ssh_mux_%h_%p_%r -M -N -f -i ./id_dsa root@$ip
checkresult
echo "Doing something…"
ssh -S /tmp/ssh_mux_%h_%p_%r root@$ip 'do something here'
checkresult
echo "Doing something else…"
ssh -S /tmp/ssh_mux_%h_%p_%r root@$ip 'do something else here'
checkresult
# Kill persistent ssh session
echo "Exiting…"
ssh -O exit -S /tmp/ssh_mux_%h_%p_%r root@$ip >/dev/null 2>&1
checkresult

There you go. In addition to being able to easily add onto this script as needed, you have a script that is completely readable to anyone who uses the shell and instantly portable to any system with Bash and OpenSSH. If some of the command flags aren’t immediately known, a simple man ssh from the shell will provide instant answers. Further, there's a built-in debugger— call the script with bash -x.

Of course, this is best used within reason — shell scripts aren’t going to cut it in many places — but I’ve seen plenty of Perl, Python, and Ruby scripts that were needlessly complicated to perform a task that would have been much simpler to install and use if they were shell scripts. Once you get into more complex data structures like arrays and dictionaries, that's where shell scripting starts to provide diminishing returns, but there are mountains of utilities that don't use those concepts.

Ultimately, it’s all about picking the right tool for the job and knowing what those tools can do. 

To comment on this article and other InfoWorld content, visit InfoWorld's LinkedIn page, Facebook page and Twitter stream.
From CIO: 8 Free Online Courses to Grow Your Tech Skills
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.