bash循环分配变量值而不覆盖先前声明的变量

时间:2014-06-27 18:27:10

标签: arrays bash variables global-variables associative-array

我们目前的设置是在配置文件中声明几个变量,然后我们运行一些依赖于这些变量的进程。我试图提供的其他功能是default_variables脚本,它将为配置文件中的所有变量提供默认值,而不会覆盖配置文件中声明的任何内容。

这是我目前的代码:

#!/bin/bash -x

# allows var to be used as an associative array
declare -A var

# variable declarations must be of the form:
# var[var_name]=var_value
# after processing loop, the above will be evaluated as:
# export var_name=var_value

# declare default variables
var[a]=a_val
var[b]=b_val
var[c]=c_val
var[d]=d_val

# iterate on associative array indices
for default_var in `echo "${!var[@]}"`
do

test_var=\$${default_var}

  # only export variables that have not been previously declared
  if [[ -z `eval $test_var` ]]
  then

    # export each index name as a variable
    export $default_var=${var[$default_var]}
  fi
done

我目前得到的错误是,如果在运行脚本之前声明了变量的值,则eval语句会尝试执行该变量的值。例如,如果上面的脚本运行了两次,那么错误将是:

-sh: a_val: command not found
-sh: b_val: command not found
-sh: c_val: command not found
-sh: d_val: command not found

现在我肯定想要一个更优雅的方法来解决这个问题,但这是我能想到的最好的方法。最后,我知道正常导出值并单独检查每个变量以查看它们是否被分配将是更多"正确"这样做的方式,但我不希望指数膨胀脚本,我不希望人们每次想要在脚本中添加新变量时都必须复制逻辑,我可以&#39 ;只需在配置文件之前运行default_variables脚本,允许它覆盖默认值,因为某些默认值取决于配置值。

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:2)

不要使用eval,这会导致其参数作为命令执行。您想要的只是$default_var命名的变量的值。间接变量引用有一个非常好的语法:

if [[ -z ${!default_var} ]]

虽然你真的想测试非空。 -z测试为空。应该是。

if [[ -n ${!default_var} ]]

此外,这是过于复杂,可以说是不正确的:

for default_var in `echo "${!var[@]}"`

只需写下:

for default_var in "${!var[@]}"

答案 1 :(得分:2)

#!/bin/bash

# allows var to be used as an associative array
declare -A var

# variable declarations must be of the form:
# var[var_name]=var_value
# after processing loop, the above will be evaluated as:
# export var_name=var_value

# declare default variables
var[a]=a_val
var[b]=b_val
var[c]=c_val
var[d]=d_val

# iterate on associative array indices
for default_var in "${!var[@]}"; do     #<=== no ugly `echo ...` needed
    [[ "${!default_var}" ]] && continue #<=== indirect expansion
    # export each index name as a variable
    export "$default_var=${var[$default_var]}" #<=== use quotes!
done

echo "a=$a"
echo "b=$b"
echo "c=$c"
echo "d=$d"

我调用了这个脚本banana

$ ./banana
a=a_val
b=b_val
c=c_val
d=d_val
$ a=gorilla ./banana
a=gorilla
b=b_val
c=c_val
d=d_val

现在这仅检查变量是否未设置或为空,即用户无法明确地将变量设为空:

$ a= ./banana
a=a_val
b=b_val
c=c_val
d=d_val

为了支持这一点,您可以改为:

for default_var in "${!var[@]}"; do     #<=== no ugly `echo ...` needed
    if ! declare -p "$default_var" &>/dev/null; then
    # export each index name as a variable
        export "$default_var=${var[$default_var]}" #<=== use quotes!
    fi
done

这样:

$ a= ./banana
a=
b=b_val
c=c_val
d=d_val

答案 2 :(得分:1)

我就是这样做的:

# iterate on associative array indices (no need to do `echo ...`)
for default_var in "${!var[@]}"
do
    # skip variables that have been previously declared (even if their value is null)
    if [[ -z ${!default_var+.} ]]
    then
        # export each index name as a variable (the safer way with quotes)
        export "$default_var=${var[$default_var]}"
    fi
done