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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.