0

I have many variables var1 var2 ... varx that may or may not be empty. I don't want to have multiple if statements and was wondering how to make a loop, to which I supply a list of variables and it checks if they are empty. If a variable is empty, its value should be set to -

11
  • What environment? Bash? Commented Sep 19, 2017 at 18:57
  • @bc2946088: Bourne shell Commented Sep 19, 2017 at 18:59
  • write this part a loop, to which I supply a list of variables at start. Then, we could help you with the rest Commented Sep 19, 2017 at 19:00
  • 3
    @hek2mgl : I don't think Bourne shell can do arrays, but its been years since I had to use it. O.P. I'm almost sure that even Bourne shell supports parameter evaluation/assignment like : ${var1:=Var1Value} .... Good luck. Commented Sep 19, 2017 at 19:08
  • 1
    @hek2mgl You should post that as an answer; IMO a long list of : ${var1:=-} statements is going to be more useful than a for loop for determining which variables are set. Commented Sep 19, 2017 at 21:11

4 Answers 4

1

This puts you into eval territory:

for var in var1 var2 varx; do
  eval 'val=$'"$var"
  if [ -z "$val" ]; then
    eval "${var}=-"
  fi
done

Note that any source that can provide arbitrary variable names can abuse this to run arbitrary code; ensure that you only use it in scenarios, like the above, where the values for var are under your control.

Sign up to request clarification or add additional context in comments.

Comments

1

As @hek2mgl first mentioned, you can assign a default value to a variable if it does not already have a value with

: ${var1:=--}
: ${var2:=--}
: ${var3:=--}
# etc

Note that this takes more space than a loop would, but it is more readable, as it doesn't require any indirection to decipher.

1 Comment

Good answer! :) Btw, can you read thoughts? I was actually not saying that, but thinking it. Especially since the ${var:-default} syntax is POSIX compatible, which seems to matter here.. I think it was @shelter who was saying that. :)
0

I solved it by creating an array arr, instead of having multiple variables ,iterating over the elements of the array and replacing empty ones with --

for element in "${!arr[@]}"; do
   out[$element]=${out[$element]:---}
 done

1 Comment

Arrays aren't supported in Bourne or POSIX sh. If this works, your shell is clearly something much more modern.
0

Bash allows you to do recursive substitution of variable names, so you can use things like ${var${suffix}}, but sh(1) doesn't, so you have to use eval expressions to allow for deferred variable expansion, like in:

#!/bin/sh

TEMPFILE="/tmp/defaults.sh-$$"
trap 'rm -f "$TEMPFILE"' 1 2 3 15

# FORMAT IS FIRST WORD IS VARIABLE NAME, REST OF LINE IF DEFAULT VALUE.
cat > "$TEMPFILE" << EOF
A default value for variable A
B default value for variable B
C default value for variable C
PATH /bin:/usr/bin
HOME $HOME
EOF

while read name value
do
    eval echo "$name==\$$name"
    if 
        [ -z "`eval echo \\\$$name`" ]
    then
        echo "$name=\"$value\""
        eval "$name=\"$value\""
    fi
done <"$TEMPFILE"

while read name dumb
do
    eval echo "[$name] =\> \$$name"
done >&2 <"$TEMPFILE"
rm -f "$TEMPFILE"

I've used a temporary file, as I make two passes through it (I did this for debugging purposes) but if you don't need the second pass, just do

#!/bin/sh

while read name value
do
    eval echo "$name==\$$name"
    if 
        [ -z "`eval echo \\\$$name`" ]
    then
        echo "$name=\"$value\""
        eval "$name=\"$value\""
    fi
done <<EOF
A default value for variable A
B default value for variable B
C default value for variable C
PATH /bin:/usr/bin
HOME $HOME
EOF

So, finally, without traces, you get something like this:

#!/bin/sh

while read name value
do
    if [ -z "`eval echo \\\$$name`" ]
    then
        eval "$name=\"$value\""
    fi
done <<EOF
A default value for variable A
B default value for variable B
C default value for variable C
PATH /bin:/usr/bin
HOME $HOME
ANOTHER_VARIABLE default value for ANOTHER_VARIABLE.
EOF

NOTE

I have tested this against GNU Bash and FreeBSD Bourne Shell. The golden test should be to test it against AT&T V7 bourne shell, but I don't have one at hand to make the tests. My apologies for that (but working on it!) :)

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.