在 shell 中解析变量中的变量

在 shell 中解析变量中的变量

我必须在bashshell 中使用环境变量并且:

  • echo $ENV解析为或DEV,具体取决于堆栈。STAGEPRD
  • echo $DEV_ACCOUNT解析为一个数字,例如echo $DEV_ACCOUNT给出12345678

我需要echo $ENV_ACCOUNT在应该解析为的命令中使用12345678,但它解析为DEV_ACCOUNT而不是12345678

我正在使用的命令:

aws events put-targets --rule {{ stack_name | lower }}-hello-world \
    --targets "Id"="1","Arn"="arn:aws:lambda:us-west-2:$ENV_ACCOUNT:function:hello-world"

正在$ENV_ACCOUNT解决DEV_ACCOUNT而不是12345678。预期输出是:

aws events put-targets --rule {{ stack_name | lower }}-hello-world \
    --targets "Id"="1","Arn"="arn:aws:lambda:us-west-2:12345678:function:hello-world"

我究竟做错了什么?

答案1

请注意,大写变量名通常不能安全使用。 $ENV例如,在许多 shell 中都是特殊的。在这些 shell 中,它的值应该是在启动某些类型的 shell 之前将获取的文件的路径名。 shell在 POSIX 模式下bash使用。$ENV

所以,在bash

declare -A account
account["develop"]=12345678
account["staging"]=9128312
account["production"]=123123

mode=$run_mode

aws events put-targets \
    --rule {{ stack_name | lower }}-hello-world \
    --targets "Id"="1","Arn"="arn:aws:lambda:us-west-2:${account[$mode]}:function:hello-wolrd"

这将设置一个关联数组 ,account用于保存开发、登台和生产模式的数据。然后,它定义我们正在使用的模式,并使用数组中的正确数据执行命令account。假定该run_mode变量是包含字符串developstaging或之一的环境变量production

关联数组是在bash4.0 中引入的。

我已经使用了您aws编写的命令(除了添加换行符和我的account变量),即使它{{ stack_name | lower }}-hello-world可能不符合您的预期(它会尝试lower作为命令执行)。因为我不知道aws,所以我不知道它应该是什么样子,但它可能应该被引用。


寻址用户 mosvy 在评论中的担忧:如果变量DEV_ACCOUNT等是环境变量,则必须根据变量的内容选择正确的变量ENV

declare -A account
account["DEV"]=$DEV_ACCOUNT
account["STAGE"]=$STAGE_ACCOUNT
account["PRD"]=$PRD_ACCOUNT

mode=$ENV

# the rest as before

答案2

我会重复一下善知识关于在 shell 脚本中不使用全部大写的变量名。这通常是一个坏主意,当变量名称与默认环境变量冲突时可能会导致问题。我也同意,最好的方法是使用关联数组,正如他在答案中所描述的那样。

无论如何,如果您坚持以这种(错误)方式而不是使用数组来执行此操作,则需要执行以下操作:

varname="$env"_account
aws events put-targets --rule {{ stack_name | lower }}-hello-world \
    --targets "Id"="1","Arn"="arn:aws:lambda:us-west-2:${!varname}:function:hello-world"

${!var}语法将扩展为名为 的变量的值var。例如:

$ foo="foovar"
$ bar=foo
$ echo ${!bar}
foovar

但说真的,不要这样做。它复杂、繁琐、难以阅读、难以维护,而关联数组将为您解决所有这些问题。

答案3

感谢所有为我的问题发布解决方案的人。我已经实现了 bash 数组来解决我的问题。但是,我的朋友建议了一个简单的解决方案

printenv `echo $ENV`_ACCOUNT

解决了我的问题。

相关内容