Welcome!

Linux Authors: Reuven Cohen, Michael Sheehan, Lavenya Dilip, Ian Thain, Bruce Armstrong

Related Topics: Linux

Linux: Article

Making C Shells Jump Through Hoops!

And creating powerful logic engines

If you've been hanging around programmers at all, you've already learned that they tend to think conditionally. Not, I hasten to say, that they conditionally think (though in some cases that might be true!) but that more than the general population, software developers are constantly musing about "if condition, then action."

What might surprise you is that the Linux shell offers identical capabilities, conditional statements that let you turn your command-line interaction - and, ultimately, your shell scripts - into powerful logic engines.

I'd like to spend some time looking at the basics of how to create conditional expressions on the command line, with the goal of being able to apply that to shell scripts too. I'll focus on Bash as it's my scripting shell of choice in the Linux (and Unix, and Mac OS X) environment, but everything we talk about is generally applicable to Csh and related shells too, albeit with slightly tweaked syntax.

Before I delve into conditionals, I hope you're starting to realize that one of the great things about choosing to learn programming by using shell scripts is that much of your learning actually takes place on a regular command line, and that as you become more sophisticated with command-line interaction (remember in my October column when we talked about >>&!, for example?), you'll also become more advanced as a shell script author. So don't get too distressed if you wonder why I haven't demonstrated even a one-line shell script several months into my column, okay?

Logical Expressions on the Command Line

Even neophyte Linux users have doubtless figured out that you can string a series of commands together by using the pipe symbol:

ls -l * | wc -l

This causes the output of the "ls -l *" command to be fed to the "wc" command as input, creating a pipeline. It's a tremendously powerful capability and one of the best reasons to learn how to be a power Linux user.

What you might not have stumbled across is that you can specify multiple commands on a line by separating them with a semicolon:

ls -l * ; wc -l

Did you catch the logical error in the above command? While the ls works fine, sending its output to the screen, the wc command will appear to freeze because it's waiting for something to count, but there's no input specified so it just reads the keyboard. Type in a few lines, press ^D (control + D), and it'll indicate how many lines you just typed in.

Those are the easy, obvious ways to put two commands together. More interestingly, you can have a conditional execution joining two commands together too, where the second is run if and only if the first failed, or if and only if the first succeeded. The first is demonstrated by:

wc -l somefile || echo "can't find somefile to count"

In this case, if the wc command returns a non-zero return code (that is, fails: see the man page for wc to see what return codes it can specify by using "man wc" on the command line), the echo statement is run. If wc succeeds, though, the echo statement isn't run and the shell is done with the command sequence.

The opposite logic is achieved with:

wc -l somefile && echo "hope that's what you expect"

where the second command, the echo, is only run if the first command, wc, returns zero, that is, returns success. It worked; it did what you wanted it to, and it didn't encounter any errors along the way.

Expressions Within Expressions

Just to make this maximally complicated, you can also collect a set of commands into an expression with parentheses, so the following is a perfectly valid and legal Linux command:

(grep dialup /var/log/modem | \
mail -s dialup taylor) || echo failed

In this final, complex example, we have a pipe that e-mails the output of a grep to the specified user with no output to the screen, unless the grep (or mail command) fails, in which case the word "failed" appears.

In daily use, the most common use for parenthesized expressions is to have a set of commands pushed into the background together:

(grep dialup /var/log/modem | mail -s dialup taylor) &

SIDEBAR
Due to an error, this column did not appear in the November issue of LWM. This article is #4 in the series and should have appeared before the December column, "Everything You Wanted to Know About the Test Command." To view the articles in the correct order, please go to http://linux.intuitive.com.

More Stories By Dave Taylor

Dave Taylor, a contributing editor to Linux.SYS-CON.com, has been involved with the Linux and Unix community since 1980 and has written a number of best-selling Unix books. Currently, he writes, teaches, and works as a management consultant to tech startups, along with his new venture, Ask Dave Taylor!, www.askdavetaylor.com and his personal blog is www.blog.Linux.SYS-CON.com. To contact Dave, please go to /www.intuitive.com/contact.shtml.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.