views:

2692

answers:

7

I've got a few Unix shell scripts where I need to check that certain environment variables are set before I start doing stuff, so I do this sort of thing:

if [ -z "$STATE" ]; then
    echo "Need to set STATE"
    exit 1
fi  

if [ -z "$DEST" ]; then
    echo "Need to set DEST"
    exit 1
fi

which is a lot of typing. Is there a more elegant idiom for checking that a set of environment variables is set?

EDIT: I should mention that these variables have no meaningful default value - the script should error out if any are unset.

A: 
MyVariable=${MyVariable:=SomeDefault}

If MyVariable is set and not null, it will reset the variable value (= nothing happens). Else, MyVariable is set to SomeDefault.

Vincent Van Den Berghe
This doesn't generate the message - and the Q says there is no default (though it didn't say that when you typed your answer).
Jonathan Leffler
Also, this is redundant: the := notation sets MyVariable if it is not set, and then the assignment redoes that.
Jonathan Leffler
Correct versions: (1) : ${MyVariable:=SomeDefault} or (2) : MyVariable=${MyVariable:-SomeDefault}
Jonathan Leffler
+2  A: 

Try this:

[ -z "$STATE" ] && echo "Need to set STATE" && exit 1;
David Schlosnagle
That's rather verbose. The semi-colon is redundant.
Jonathan Leffler
+2  A: 

Your question is dependent on the shell that you are using.

Bourne shell leaves very little in the way of what you're after.

BUT...

It does work, just about everywhere.

Just try and stay away from csh. It was good for the bells and whistles it added, compared the Bourne shell, but it is really creaking now. If you don't believe me, just try and separate out STDERR in csh! (-:

There are two possibilities here. The example above, namely using:

${MyVariable:=SomeDefault}

for the first time you need to refer to $MyVariable. This takes the env. var MyVariable and, if it is currently not set, assigns the value of SomeDefault to the variable for later use.

You also have the possibility of:

${MyVariable:-SomeDefault}

which just substitutes SomeDefault for the variable where you are using this construct. It doesn't assign the value SomeDefault to the variable, and the value of MyVariable will still be null after this statement is encountered.

HTH.

cheers,

Rob

Rob Wells
Mr.Ree
The Bourne shell does what is required.
Jonathan Leffler
The MyVariable=${MyVariable:=SomeDefault} notation is redundant - see also my comments to Vincent Van Den Bergh's answer too.
Jonathan Leffler
@Jonathan - you're right. I've edited my response.
Rob Wells
A: 

I always used:

if [ "x$STATE" == "x" ]; then echo "Need to set State"; exit 1; fi

Not that much more concise, I'm afraid.

Under CSH you have $?STATE.

Mr.Ree
+10  A: 

The obvious answer is:

: ${STATE?"Need to set STATE"}
: ${DEST:?"Need to set DEST non-empty"}

The first requires STATE to be set, but STATE="" (an empty string) is OK - not exactly what you want, but the alternative and older notation.

The second requires DEST to be set and non-empty.

If you supply no message, the shell provides a default message.

The ${var?} construct is portable back to Version 7 UNIX and the Bourne Shell (1978 or thereabouts). The ${var:?} construct is slightly more recent: I think it was in System III UNIX circa 1981, but it may have been in PWB UNIX before that. It is therefore in the Korn Shell, and in the POSIX shells, including specifically Bash.

I should probably add that the colon command simply has its arguments evaluated and then succeeds. It is the original shell comment notation (before '#' to end of line). For a long time, Bourne shell scripts had a colon as the first character. The C Shell would read a script and use the first character to determine whether it was for the C Shell (a '#' hash) or the Bourne shell (a ':' colon). Then the kernel got in on the act and added support for '#!/path/to/program' and the Bourne shell got '#' comments, and the colon convention went by the wayside. But if you come across a script that starts with a colon, now you will know why.

Jonathan Leffler
That's the thing I need. I've been using various versions of Unix since 1987 and I've never seen this syntax - just goes to show...
AndrewR
A: 

This can be a way too

if (set -u; : $HOME) 2> /dev/null ... ..

http://unstableme.blogspot.com/2007/02/checks-whether-envvar-is-set-or-not.html

A: 

The $? syntax is pretty neat:

if [ $?BLAH == 1 ]; then 
    echo "Exists"; 
else 
    echo "Does not exist"; 
fi
Graeme