0

I have a string of variables to check, and a string of default values like follows:

variables_to_check="name surname address"
variables_default_values="John Doe Paris"

Here is what I would like to do :

  1. Check if $name is set, if not, give it John as a value
  2. Check if $surname is set, if not, give it Doe as a value
  3. ...

Here is the current non-working code I have :

variables_to_check="name surname address"
variables_default_values="John Doe Paris"
i=0
for variable in $variables_to_check
do
    ((i++))
    if [[ -z ${"$variable"+x} ]] #this line doesn't seem to work
                                 #inspired from http://stackoverflow.com/questions/3601515
    then
        default=$(echo $variables_default_values | cut -d " " -f $i)
        set_config $variable $default
        declare "$variable=$default" #this doesn't seem to work either
                                     #inspired from http://stackoverflow.com/questions/16553089
    fi
done

Any help would be greatly appreciated

Magix
  • 4,989
  • 7
  • 26
  • 50
  • What version of `bash` can you use? – chepner Jul 01 '16 at 13:49
  • I am currently running `bash` version `4.3.30`, but the system will be kept updated - that is, I can use the latest version of `bash` if needed – Magix Jul 01 '16 at 13:51
  • Look up `${!variable}` under Bash [shell parameter expansions](https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion). – Jonathan Leffler Jul 01 '16 at 13:58

3 Answers3

1

Use the -v operator to determine if a variable is set. This is also much easier if you use arrays to store the names and default values.

variables=(name surname address)
default_values=(John Doe "somewhere in Paris")

for ((i=0; i < ${#variables[@]}; i++)); do
    if ! [[ -v ${variables[i]} ]]; then
        declare "${variables[i]}=${default_values[i]}"
    fi
done

bash 4.3 or later is required for -v to work with arrays.

Namerefs (also introduced in 4.3) can make this a little simpler:

for ((i=0; i < ${#variables[@]}; i++)); do
    declare -n name=${variables[i]}
    [[ -v name ]] && name=${default_values[i]}"
done

Unless the variable and default value lists are being generated programmatically, a little duplication will be much more readable and not really any harder to maintain:

# This will also work in any POSIX-compliant shell, not just
# in a sufficiently new version of bash
: ${name:=John}
: ${surname:=Doe}
: ${address:=somewhere in Paris}
chepner
  • 497,756
  • 71
  • 530
  • 681
1

You may use "namerefs" to do this:

variables=( a b c d e )
c=1
d=7

value=42

declare -n var

for var in ${variables[@]}; do
    if [[ ! -v var ]]; then
        var=$value
    fi
done

echo $a, $b, $c, $d, $e

Running it:

$ bash script.sh
42, 42, 1, 7, 42

Within the loop, the var variable is a name reference to the variables named in the array variables which means that you may use var as the named variable.

Use -v to see if the variable is set or not, and if it's not, assign a value to it. The whole if-statement may also be replaced with the single line

: ${var:=$value}

(the : is a no-op command that evaluates its arguments, and the evaluation of the argument has the side effect that the shell assigns a value to the variable var if it is unset).

EDIT: The following is the same thing, but with separate default values for each of the variables:

variables=( a b c d e )
defaults=( 1 2 3 4 5 )

c=1
d=7

for (( i = 0; i < ${#variables[@]}; ++i )); do
        declare -n var="${variables[$i]}"
        value="${defaults[$i]}"

        : ${var:=$value}
done

echo $a, $b, $c, $d, $e

Running it:

$ bash script.sh
1, 2, 1, 7, 5
Kusalananda
  • 14,885
  • 3
  • 41
  • 52
  • wow, very nest trick using `:`. However it does only work when only one default value is needed, not when a whole array of default values should apply. – Magix Jul 01 '16 at 14:15
  • @Magix Well, that's what we use the loop for :-) – Kusalananda Jul 01 '16 at 14:25
  • What i mean is, what if I want different defaults for `a`, `b`, `c`, `d`, `e` and `f` ? The `:` trick becomes unusable, doesn't it? – Magix Jul 01 '16 at 14:29
  • Alright, great job. Accepted your answer instead of @Chepner's one because, well, great trick ! – Magix Jul 01 '16 at 15:03
0

The shell has some lovely string substitution operators which will do that, but there is a third possibility you do not list above: variable is set to value "".

Expression     "var Set not Null"   "var Set but Null"  "var Unset"
${var-DEFAULT}      var                 null             DEFAULT    
${var:-DEFAULT}     var                 DEFAULT          DEFAULT
${var=DEFAULT}      var                 null             DEFAULT    
${var:=DEFAULT}     var                 DEFAULT          DEFAULT    
${var+OTHER}        OTHER               OTHER            null   
${var:+OTHER}       OTHER               null             null   

So in your cases, you would want something like:

${name:-"John"}   # or ${name:="John"} 
${surname:-"Doe"} # or ${surname:="Doe"}

and so on.

Shadowfen
  • 459
  • 4
  • 11