如何使用变量的值作为动态变量名称?

如何使用变量的值作为动态变量名称?

我一直在四处寻找这个问题,但要么我不知道如何正确地提出问题,要么这不是一个足够常见的问题......

在 PHP 中,这(几乎)是微不足道的:

function getSite(string $prefix = 'prod') {
  $DEV_SITE='dev.site.com';
  $PROD_SITE='www.site.com';
  
  $site = strtoupper("{$prefix}_site");

  return ${$site};
}

getSite();      // www.site.com
getSite('dev'); // dev.site.com

我会尝试逐步实现它。

我有一组带_SITE后缀的变量。

DEV_SITE=dev.site.com
PROD_SITE=www.site.com

我想调用一个脚本,仅使用前缀作为参数,默认为 PROD。

#!/bin/bash

PREFIX=${1:-PROD}

echo $PREFIX
---

$ script.sh dev
dev
$ script.sh
PROD

我想附加"_SITE"$PREFIX获取我的变量名称之一:

VAR_NAME="${1:-PROD}_SITE"
echo $VAR_NAME
---

$ script.sh dev
dev_SITE
$script.sh
PROD_SITE

啊www,dev_SITE无效,但我不希望呼叫者需要知道其中的区别。

因此,让我们将参数设置为“不区分大小写”,以便dev将其转换为匹配变量名称:

SITE="${1:-PROD}_SITE"
# This does NOT work:
SITE="${1:-PROD^^}_SITE"
echo ${SITE^^}
---

$ script.sh dev
DEV_SITE
$script.sh
PROD_SITE

伟大的。但获得的最简单方法是什么价值那个名字的?

我尝试过的所有操作${SITE^^}都会给我带来“错误替换”错误。

echo ${$SITE^^}_PROD
echo ${${!SITE^^}_PROD}
echo ${"${SITE^^}_PROD"}
echo ${"${!SITE^^}_PROD"}

等等...

如果我分配并重新分配,它会起作用:

SITE="${1:-PROD}_SITE"
SITE=${!SITE^^}
echo $SITE
---

$ script.sh dev
dev.site.com
$ script.sh
prod.site.com

我相信这与一步完成的所有替换有关,但我也尝试过使用子 shell 并将名称通过管道传递到其他命令中,但无法理解它。

答案1

您可以使用nameref.

从当前的bash联机帮助页来看:

可以使用声明或本地内置命令的 -n 选项(请参阅下面的声明和本地的描述)为变量分配 nameref 属性,以创建 nameref 或对另一个变量的引用。这允许间接操纵变量。每当 nameref 变量被引用、赋值、取消设置或修改其属性(除了使用或更改 nameref 属性本身)时,实际上都会对 nameref 变量值指定的变量执行操作。 nameref 通常在 shell 函数中使用来引用其名称作为参数传递给函数的变量。例如,如果将变量名作为第一个参数传递给 shell 函数,则运行

         declare -n ref=$1

在函数内部创建一个 nameref 变量 ref,其值是作为第一个参数传递的变量名。对 ref 的引用和赋值以及对其属性的更改,均被视为对名称传递为的变量的引用、赋值和属性修改1 美元。如果 for 循环中的控制变量具有 nameref 属性,则单词列表可以是 shell 变量列表,并且在执行循环时将为列表中的每个单词建立名称引用。不能为数组变量赋予 nameref 属性。但是,nameref 变量可以引用数组变量和下标数组变量。可以使用 unset 内置命令的 -n 选项来取消设置 Namerefs。否则,如果以 nameref 变量的名称作为参数来执行 unset,则 nameref 变量引用的变量将被取消设置。

这是使用 nameref 的脚本版本。

#!/bin/bash

set -u

PROD_SITE='prod.example.com'
DEV_SITE='dev.example.com'
PREFIX=${1:-PROD}
SITEVAR=${PREFIX^^}_SITE

declare -n SITE=$SITEVAR

printf "Site is '%s'.\n" "${SITE}"

答案2

我有一组带有 _SITE 后缀的变量。

如果可以的话,不要这样做。如果可能的话,请使用关联数组(类似于基本数组,但索引是字符串)。这打印www.site.com

declare -A sites=([dev]=dev.site.com [prod]=www.site.com)
site=prod
echo "${sites[$site]}"

答案3

正如您所展示的,Bash 提供了一个取消引用实用程序(“给我与其名称相等的变量的值”),这使得这相对简单。尽管检查无效选择可能超出了本范围,但set -u如果引用了不存在的变量,则使用将导致脚本中止:

$ ./625908.sh dev
Prefix is 'DEV'.
Site is 'dev.example.com'.
$ ./625908.sh fake
Prefix is 'FAKE'.
./625908.sh: line 9: !SITEVAR: unbound variable

所以,看看这个脚本:

#!/bin/bash
set -u
PROD_SITE='prod.example.com'
DEV_SITE='dev.example.com'
PREFIX=${1:-PROD}
PREFIX=${PREFIX^^} # Squash to uppercase
printf "Prefix is '%s'.\n" "${PREFIX}"
SITEVAR="${PREFIX}_SITE"
SITE="${!SITEVAR}"
printf "Site is '%s'.\n" "${SITE}"

这可以简化一些,但不是很多:

#!/bin/bash
set -u
PROD_SITE='prod.example.com'
DEV_SITE='dev.example.com'
PREFIX=${1:-PROD}
SITEVAR=${PREFIX^^}_SITE
SITE="${!SITEVAR}"
printf "Site is '%s'.\n" "${SITE}"

相关内容