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 -
4 Answers
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.
Comments
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
${var:-default} syntax is POSIX compatible, which seems to matter here.. I think it was @shelter who was saying that. :)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
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!) :)
: ${var1:=Var1Value} ....Good luck.: ${var1:=-}statements is going to be more useful than aforloop for determining which variables are set.