eval 在 shellscript 中不起作用

use*_*241 3 shell

我正在尝试使用 获取在运行时按名称选择的变量的值eval,但如果-名称中包含(连字符),则无法获取其值。

ENV=dev
REGION=us-east-1

DBUSERNAME=DB_USER_${ENV}_$REGION
DBPASSWORD=DB_PASS_${ENV}_$REGION

eval "USERNAME=\${${DBUSERNAME}}"
eval "PASSWORD=\${${DBPASSWORD}}"

echo USERNAME=$USERNAME
echo PASSWORD=$PASSWORD
Run Code Online (Sandbox Code Playgroud)

结果

echo USERNAME=east-1
echo PASSWORD=east-1
Run Code Online (Sandbox Code Playgroud)

预期结果

echo USERNAME=DB_USER_dev_us-east-1
echo PASSWORD=DB_USER_dev_us-east-1
Run Code Online (Sandbox Code Playgroud)

如果名称中没有连字符,则工作正常。

Tob*_*ght 5

调查

我们可以通过在 shell 中运行它并-x选择跟踪执行来查看发生了什么:

$ sh -x ./36332134.sh 
+ ENV=dev
+ REGION=us-east-1
+ DBUSERNAME=DB_USER_dev_us-east-1
+ DBPASSWORD=DB_PASS_dev_us-east-1
+ eval USERNAME=${DB_USER_dev_us-east-1}
+ USERNAME=east-1
+ eval PASSWORD=${DB_PASS_dev_us-east-1}
+ PASSWORD=east-1
+ echo USERNAME=east-1
USERNAME=east-1
+ echo PASSWORD=east-1
PASSWORD=east-1
Run Code Online (Sandbox Code Playgroud)

请注意,这eval USERNAME=${DB_USER_dev_us-east-1}给了我们USERNAME=east-1. 这实际上是参数扩展,如 Bash 手册中所述:

当不执行子字符串扩展时,使用下面记录的形式(例如,:-),bash 测试未设置或为空的参数。省略冒号会导致仅对未设置的参数进行测试。

${parameter:-word}
使用默认值。如果parameter未设置或为空,word则替换的扩展。否则,将parameter 替换的值。

由于$DB_USER_dev_us未设置,则扩展${DB_USER_dev_us-east-1}east-1

解决方法

Shell 不允许-变量名(包括环境变量)。我猜DB_USER_dev_us-east-1是由一些非shell程序设置的?在这种情况下,我认为您需要一个类似的非外壳程序来检索它。我测试了引用-,但无济于事。

如果可以使用 Bash 作为 shell,则可能需要使用关联数组而不是组合变量名称。

如果您能够更改环境变量,您可以考虑更改-to (say) _,然后使用 (Bash)${REGION//-/_}或(否则)tr来转换名称:

REGION="${REGION//-/_}"            # Bash
REGION="$(echo "$REGION"|tr - _)"  # POSIX
Run Code Online (Sandbox Code Playgroud)