3

I need to test if certain environment variables are set before running my script. I'm using a technique from this answer:

if  [ -z ${var1+x} ]
    echo "var1 not set"
    exit 1
fi

This works well for string variables, but there's a parameter which needs to be an array. It has to be set, but could be empty.

foo=("foo" "bar" "baz")
[ -z ${foo+x} ] # false
bar=()
[ -z ${bar+x} ] # true
[ -z ${baz+x} ] # also true

So, my question is how do I declare an empty array to make it distinct from unset variable. I'd also like to test if variable is array (whether empty or not) or non array (whether set or unset).

4
  • [ -z ${bar+x} ] returns true. Are you sure you tested all those commands? Commented Jan 31, 2020 at 10:43
  • @oguzismail for me it returns false. Are you using bash or some other shell? Commented Jan 31, 2020 at 10:46
  • I use bash 5.0.11. So you're saying unset xxx; [ -z ${xxx+x} ] && echo true does not print anything on your shell? Commented Jan 31, 2020 at 10:48
  • 1
    @oguzismail yes, you've been right, I've updated my question so now it's correct. By true I've meant "variable is set", which is surely misleading when I think about it Commented Jan 31, 2020 at 10:55

3 Answers 3

5

You can use declare -p to find out what type a variable is.

scalar=1
declare -p scalar  # declare -- scalar="1"
arr=(1 2 3)
declare -p arr     # declare -a arr=([0]="1" [1]="2" [2]="3")

Undeclared variable will exit with value 1:

unset arr
declare -p arr  # bash: declare: arr: not found
echo $?         # 1

To test whether an array is empty, test ${#arr[@]}.

arr=(1 2 3)
echo ${#arr[@]}  # 3
arr=()
echo ${#arr[@]}  # 0
Sign up to request clarification or add additional context in comments.

1 Comment

How does this distinguish from an empty array to a unset variable ?
4

You can use declare -p to check the variable type

$ list=()
$ declare -p list
declare -a list='()'

If the output contains "-a" your var is an array, even if empty

3 Comments

So, to test it I have to do something like if [[ $(declare -p var1) =~ "-a" ]]?
I did it as [[ ! $(declare -p var1 2>/dev/null || true) =~ "-a" ]], this way it does not fall when var1 is not set and does not provide error message. Quite ugly but working.
Nice catch. I thought it would return an error code and lead to error, but it is redundant.
1

Or use this method

[[ ${var[@]@A} =~ '-a' ]] && echo array || echo variable

Based on this

$ man bash
...
       ${parameter@operator}
              Parameter transformation.  The expansion is either a transformation of the value of parameter or information about parameter itself, depending
              on the value of operator.  Each operator is a single letter:

              Q      The expansion is a string that is the value of parameter quoted in a format that can be reused as input.
              E      The expansion is a string that is the value of parameter with backslash escape sequences expanded as with the $'...' quoting mechansim.
              P      The expansion is a string that is the result of expanding the value of parameter as if it were a prompt string (see PROMPTING below).
              A      The  expansion  is  a string in the form of an assignment statement or declare command that, if evaluated, will recreate parameter with
                     its attributes and value.
              a      The expansion is a string consisting of flag values representing parameter's attributes.

              If parameter is @ or *, the operation is applied to each positional parameter in turn, and the expansion is the resultant list.  If  parameter
              is  an  array variable subscripted with @ or *, the case modification operation is applied to each member of the array in turn, and the expan‐
              sion is the resultant list.

              The result of the expansion is subject to word splitting and pathname expansion as described below.
...

Comments

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.