1

I have been creating a small library of bash functions to encapsulate some of the more arcane bash syntax structures into routines that I can quickly use and reference. But for some of them, I'm running into unexpected return codes from my functions. The 'is_undefined' function below is one such example. Can anyone explain the results I am getting? (Also provided below.)

#!/bin/bash

is_undefined ()
{
  # aka "unset" (not to be confused with "set to nothing")
  # http://stackoverflow.com/questions/874389/bash-test-for-a-variable-unset-using-a-function
  [ -z ${1+x} ]
}

if [ -z ${UNDEFINED+x} ]; then
  echo "inline method reports that \$UNDEFINED is undefined"
fi

if is_undefined UNDEFINED; then
  echo "is_undefined() reports that \$UNDEFINED is undefined"
else
  echo "is_undefined() reports that \$UNDEFINED is defined"
fi

DEFINED=
if is_undefined DEFINED; then
  echo "is_undefined() reports that \$DEFINED is undefined"
else
  echo "is_undefined() reports that \$DEFINED is defined"
fi

The surprising results are:

$ ./test.sh
inline method reports that $UNDEFINED is undefined
is_undefined() reports that $UNDEFINED is defined
is_undefined() reports that $DEFINED is defined
4
  • 1
    add set -vx to see how/what is being processed when. Good luck. Commented Dec 6, 2013 at 23:05
  • The newest version of bash has a -v operator to test if a variable is set. [[ -v foo ]] succeeds only if foo is not set; if foo is set to the empty string it fails. Commented Dec 6, 2013 at 23:16
  • Regarding -v: I managed to get that into my code several months back, but forgot to document a reference. I removed it last night because I failed to find it mentioned in my bash book, and googling it yielded no results. I thought I must have imagined it... I guess not! :) Commented Dec 6, 2013 at 23:19
  • 1
    Oh, and my description of -vis completely backwards :( -v foo is true when foo is set, and false otherwise. Introduced in 4.2. Commented Dec 6, 2013 at 23:45

2 Answers 2

3

inside is_undefined you are testing $1, not ${UNDEFINED}, to do that you need throw in variable indirection like

is_undefined () {
    [ -z "${!1+x}" ]
}

However, that is bashism and not posix compliant. For posix compliacy you will need

is_undefined () {
    eval "[ -z \${$1+x} ]"
}
Sign up to request clarification or add additional context in comments.

Comments

3

is_undefined UDEFINED returns true, because the test inside is_undefined doesn't test UNDEFINED but $1, and $1 is defined. It's value is UNDEFINED.

So, your function should always return true, as long as you provide a parameter. The only time it will return false, should be when you call it with no arguments

is_undefined

To get is_undefined test the actual variable, you can use variable indirection with an exclamation mark !, see Shell Parameter Expansion

is_undefined ()
{
  # aka "unset" (not to be confused with "set to nothing")
  # http://stackoverflow.com/questions/874389/bash-test-for-a-variable-unset-using-a-function
  [ -z "${!1+x}" ]
}

4 Comments

That makes sense. But what must I do to dereference $1 within that expression inside is_undefined(), to get the behavior I desire?
You can use variable indirection, see updated answer.
Thanks! (Meta: I am uncertain whether to accept your answer, or @yaccz's answer. He provided the variable indirection component slightly before you did, but both of your answers were equally helpful. What's etiquette, in this scenario?)
I don't know about any etiquette, in the end it's up to you. In either case, I won't mind, if you accept his answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.