Wednesday, September 23, 2009

Variables Without Values

Often, you only want to do something if a variable is unset.

I see code to handle such conditions that looks like this.
if [ "A$foo" = "A" ]
then
take-some-action
fi
It's either old code or code by old programmers.

The test is how you used to have to ask whether a variable was empty. Here's a newer idiom.

[ "$foo" ] || take-some-action
The test operator, [ ], comes in many flavors. For example
[ -d $X ] asks "Does $X name a directory?"

In its simplest form, though,

[ $X ]
asks "Is $X empty?" The test returns true if $X has something in it, false if it doesn't. The new code does the same thing as the old, but it's shorter and, arguably, easier to read.

But why not this?

[ $foo ] || take-some-action
Ah. Because if foo='1 2 3', then test complains that you've given it too many arguments.

[: 2: unary operator expected
One more trick: what if you're running with "set -u", which complains whenever it stumbles on an unset variable, with complaints like this
line 3: foo: unbound variable

Write the test like this:
["${foo-}" ] || take some action
If $foo is unset, ${foo-} has a null value. "Null" is a value; "unset" really means the variable was never set. So, with "${foo-}" the shell won't complain about an unset variable, but the test will still fail.

This is still shorter than the example we started with, but it's only more readable once you can read the idiom ${foo-} without stumbling.

On the other hand, the first example will also choke if $foo is unset, so it would also have to be modified like this:
if [ "A${foo-}" = "A" ]
then
take-some-action
fi

No comments: