Shell Is Underrated

Most professional computer programmers have some exposure to Bourne shell programming. It’s a staple of system administration and devops work. But many programmers outside of those areas treat it as an afterthought. If that describes you, then you miss out on something useful and important. And this article is for you.

Why Shell Is Useful

When you want to automate multi-step data transformations, quickly script a sequence of program invocations for repeated use, shell is one of the best tools around. You can use it to invoke any external program with minimal setup and overhead.

Bourne shell and its various flavors like bash are both simple and ubiquitous. Every Apple desktop and laptop, every Linux box, every variant of BSD, comes with a shell. You can install a terminal emulator on your Android phone and gain access to a shell. While the different flavors are not fully compatible, the basic functionality is the same across the entire family.

Why Shell Is Important

Programming in shell will acquaint you with unix style programming, an approach that employs a large toolkit of simple programs to solve problems. The same tools, used one way and another solve one problem or another. Typically, shell is the mechanism to deploy other tools in that solution.

Shell also provides a wonderful form of high-level modularity in the form of unix filters and pipelines. A unix filter is a program that reads input from standard input, writes data it to standard output, and logs to standard error. The unix pipeline is a shell composition feature in which standard output from an upstream program feeds into the standard input of a downstream program. Under this operation, the composition of two unix filters is itself a unix filter.

Why Shell Is Fun

Here’s a simple example of what you can do in shell. We’ll write three shell functions that you can use at the command line or in a shell script. Best to try them as you read.

The first function is called shout:

shout() { echo "$0: $*" >&2; }

This function logs the name of the calling program ($0) and whatever arguments it was given ($*) to standard error. You can type in the definition at the command line and then exercise it immediately

shout here you are

Contratulations! You’ve written a shell function. If you tried this example from the command line you may have seen something unexpected in the output corresponding to the calling program name. Figuring that out is left to you.

Now let’s define a second function, this one called barf:

barf() { shout "fatal: $*"; exit 111; }

This function shouts about its fatality and then exits with a recognizable error code. Try it from the command line in a subshell:

( barf this is the end )

And while you’re at it, confirm the exit code:

echo $?

Congratulations! You now have two shell functions under your belt. For the curious, the exit code choice comes from qmail.

Now let’s finish up with one final function called safe:

safe() { "$@" || barf "cannot $*"; }

This invokes its arguments as a program (with arguments). If that invocation fails, then it barfs, complaining that it cannot execute. Try it with a program that works, and one that doesn’t:

safe echo hello there
safe echoo hello there

What can you accomplish with these functions? By virtue of extending your shell vocabulary by use of safe you can now easily write shell scripts that report errors uniformly and robustly:

safe program1 args | safe program2 args

These functions are cool, fun, and useful!

Write Your Own

Here are the three function definitions gathered together:

shout() { echo "$0: $*" >&2; }
barf() { shout "fatal: $*"; exit 111; }
safe() { "$@" || barf "cannot $*"; }

Study these functions and understand the details of how they work. Look at the use of variables $0, $*, $@. Understand the redirection of output to standard error. Learn how argument passing to functions works and how safe invokes its program arguments. Understanding these three simple functions will leave you more knowledgeable about shell than perhaps 75% of those who use it. And you’ll have three cool new tools in your unix kit.

Don’t lose sight of how simple these functions are. That’s one of their best characteristics. Once you’ve mastered these functions, you’re ready to create your own function and extend your shell vocabulary. Keep it simple, make it useful, and please share it here.

comments powered by Disqus