我一直在四处寻找这个问题,但要么我不知道如何正确地提出问题,要么这不是一个足够常见的问题......
在 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}"