Welcome!

Linux Authors: Michael Sheehan, Lavenya Dilip, Ian Thain, Bruce Armstrong, Ellen Rubin

Related Topics: Linux

Linux: Article

String and Numeric Test Statements

Looping and flow control

Last month I talked about the file-related options to the test command and how that helps you create smart and sophisticated shell scripts. This time I want to look at the additional conditions available for looping and flow control.

String Tests

One common test in shell scripts is to ascertain whether something the user has typed in or something pulled out of a data stream or file matches a specific pattern or string. The first of these tests is -z $string, which returns true if the string is zero length, false otherwise. Consider this snippet:


empty=""

if [ -z $empty ] ; then
  echo the length of empty is zero
else
  echo the length of empty is non-zero
fi

You can easily experiment and verify that if you set the variable empty to anything at all, the test will be nonzero, and if you leave it blank (or don't have it as a defined variable at all, for that matter) it'll be considered zero.

Somewhat confusingly, string tests in the test program (that is, string tests for shell scripts overall) are done with the following four operators: =, !=, <, or >. If you want to test a variable to see if it's a certain value, here's how that would look:

if [ $yourvar = "quit" ] ; then

The concept of less than or greater than is worth a bit of explanation too: it's an ASCII comparison, so "cat" is less than "dog," but, since it's ASCII, it also means that "+++" is less than "aardvark" too. Logically, this test should then work:

if [ "+++" < "aardvark" ] ; then

In fact, that'll fail with an annoying error message "-bash: aardvark: No such file or directory." This is happening because the shell is parsing and interpreting the < as a file redirection symbol before it even hands the arguments to the test command. Annoying! To sidestep this, escape the angle bracket like this:

if [ "+++" \< "aardvark" ] ; then

To be honest, though, you won't see this very often. Much more common are the = or != notations.

To get input from the user, the shell has the read command. Here's an example of using read and a string test conditional:


echo -n "Your first name: "
read answer

if [ $answer = "Dave" ] ; then
  echo Hello Dave
else
  echo Too bad you are not Dave
fi

The one problem to be aware of with string tests is that if the variable isn't defined, doesn't have any value, or has a value that includes a space, you can end up with a syntax error. On the previous snippet, for example, entering "Super Guy" as the name produces:

test.sh: line 6: [: too many arguments

Fortunately you can sidestep this problem by making sure that you quote the variable reference. Use double quotes, though, because single quotes will prevent the variable from being expanded at all. Here's the fixed line:

if [ "$answer" = "Dave" ] ; then

Numeric Tests

The other type of test you might want to use is numeric, and this will be like a quick flashback to BASIC, if you've been around that long. The tests are -lt, -le, -eq, -ne, -gt, -ge, for less than, less than or equal, equal, not equal, greater than, or greater than or equal, respectively. Want to see if an input value is less than 10? Try this:

if [ "$input" -lt 10 ] ; then

What's unfortunate is that there isn't a simple built-in test for whether values match specific criteria (for example, integer only), but with some creative thought and a little subshell transformation trick, almost all tests can be easily done. To ensure that a value is an integer, here's how I'd approach the problem:


nonums="$(echo $answer | 
  sed 's/[0-9]//g')"
if [ ! -z "$nonums" ] ; then
  echo "Not an integer value."
  exit 0
fi

The basic idea is that we delete all digits in the string, then use the ! -z test (the "!" reverses the logic of the test) to see if the resultant string is zero or not. Put in the context of an actual - albeit simple - script, here's how this would look:


echo -n "Pick a number between 1 and 20: "
read answer

nonums="$(echo $answer | 
  sed 's/[0-9]//g')"
if [ ! -z "$nonums" ] ; then
  echo "Not an integer value."
  exit 0
fi

if [ $answer -lt 10 ] ; then
  echo "Your answer is less than ten"
else
  echo "Your answer is not less than ten"
fi

Let's wrap up here for now, and next month we'll look at more sophisticated loop control options, and perhaps begin building a numeric guessing game as a fun and interesting example script.

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.