2

I have an array of variables. I want to check if the variables have a value using the for loop.

I am getting the values into loop but the if condition is failing

function check {
    arr=("$@")
    for var in "${arr[@]}"; do
        if [ -z $var ] ; then
            echo $var "is not available"
        else
            echo $var "is available"
        fi
    done
}

name="abc"
city="xyz"
arr=(name city state country)
check ${arr[@]}

For the above I am getting all as available

Expected output is

name is available
city is available
state is not available
country is not available
1
  • var in your loop takes on the values name, city, state and country. [ -z ... ] tests whether the length of the argument is zero. None of those words has zero length, so the else branch is taken every time. Commented Feb 28, 2020 at 11:42

3 Answers 3

4

This is the correct syntax for your task

if [ -z "${!var}" ] ; then
    echo $var "is not available"
else
    echo $var "is available"
fi

Explanation, this method uses an indirect variable expansion, this construction ${!var} will expand as value of variable which name is in $var.

Changed check function a bit

check () {
    for var in "$@"; do
        [[ "${!var}" ]] && not= || not="not "
        echo "$var is ${not}available"
    done
}

And another variant using declare

check () {
    for var in "$@"; do
        declare -p $var &> /dev/null && not= || not="not "
        echo "$var is ${not}available"
    done
}

From declare help

$ declare --help
declare: declare [-aAfFgilnrtux] [-p] [name[=value] ...]
    Set variable values and attributes.
    Declare variables and give them attributes.  If no NAMEs are given,
    display the attributes and values of all variables.
    ...
    -p  display the attributes and value of each NAME
    ...

Actually all vars can be checked at once using this

check () {
    declare -p $@ 2>&1 | sed 's/.* \(.*\)=.*/\1 is available/;s/.*declare: \(.*\):.*/\1 is not available/'
}
Sign up to request clarification or add additional context in comments.

5 Comments

It would be great if you can explain the change.
-z string True if the length of string is zero.
This has a bug - variables with values with spaces will result in an error message from test.
If space isn't valid value than it's not a bug it's a feature)
And i just followed OPs style
0

While indirection is a possible solution, it is not really recommended to use. A safer way would be to use an associative array:

function check {
    eval "declare -A arr="${1#*=}
    shift
    for var in "$@"; do
        if [ -z "${arr[$var]}" ] ; then
            echo $var "is not available"
        else
            echo $var "is available"
        fi
    done
}

declare -A list
list[name]="abc"
list[city]="xyz"

check "$(declare -p list)" name city state country

This returns:

name is available
city is available
state is not available
country is not available

The following question was used to create this answer: How to rename an associative array in Bash?

Comments

0

For newer Bash versions (I think ~4.3), there's no need to use eval or any other abundant code.

Checking, if an array has any contents, is as simple as:

if [[ ${array[@]} ]]; then
    echo -e "Array has ${#array[@]} elements"
fi

Any whitespace elements will also count as content here; to ignore them, one could either use a whitespace-negating RegEx in the condition test, or iterate over the array and check each element.

There's also the possibility to use named references, to avoid superfluous array value copying and expansions, when passing arrays as arguments to functions:

declare -a emptyArray
declare -a array=( TEST1 TEST2 TEST3 )
declare -a onlyBlanksArray=('   ' ' ' '  ')
declare -a withBlanksArray=('   ' ' 1 ' '  ')

# Checks if an array has blank/non-blank elements (is non-empty)
has_elements() {
    local -n aRef="$1"
    [[ ${aRef[@]} ]]
}

# Checks if an array contains only blank elements
has_only_blanks() {
    local -n aRef="$1"
    [[ ${aRef[@]} == +([[:space:]]) ]]
}

if has_elements array; then
    echo -e "Array has ${#array[@]} elements"
fi

if ! has_elements emptyArray; then
    echo -e "ARRAY IS EMPTY"
fi

if has_only_blanks onlyBlanksArray; then
    echo -e "Is blanks-only array"
fi

if ! has_only_blanks withBlanksArray; then
    echo -e "ARRAY CONTAINS NON-BLANK ELEMENTS"
fi

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.