【问题标题】:bash loop to assign variables values without overwriting previously declared variablesbash循环分配变量值而不覆盖先前声明的变量
【发布时间】:2014-06-27 18:27:09
【问题描述】:

我们目前的设置是在配置文件中声明几个变量,然后我们运行一些依赖于这些变量的进程。我试图提供的附加功能是一个 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

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

提前感谢您的帮助!

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    此外,这过于复杂,而且可能是不正确的:

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

    只写:

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

    【讨论】:

    • 完全正确,先生!除了 -n 选项,我想测试空,因为如果它是空的,那么我想分配一个值,否则跳过它,但是 ${!default_var} 完成了这项工作,并且确实不需要 echo 命令.因为我在嵌套变量,所以我试图在我的脚本初稿时过于谨慎:)
    • 啊,我现在看到,就 -n/-z 而言,我发表的评论实际上误导了我的意图。我将其改写为“仅导出先前未声明的变量”
    【解决方案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
    

    【讨论】:

      【解决方案3】:

      我会这样做:

      # 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
      

      【讨论】:

      • [[ ! -v $default_var ]]。 fwiw。
      • @rici True 但仅开始 bash 4.2
      • 是的。只有三分之一的十年。当然,仍然有人认为 C99 太新奇而无法使用。 :)
      • @rici 我希望你不要开玩笑地假设所有用户都可以轻松升级他们的系统。
      • 一点也不。我自己仍然使用电传打字机与大型机进行通信,就像我开始从事该领域以来所做的那样。虽然我的手指越来越疲倦,但没有咔哒声就感觉不对劲。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      • 1970-01-01
      • 2018-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多