Bash - 将“嵌套”变量的值存入另一个变量中 [编辑:间接变量扩展]

5
我尝试将一个“嵌套”的变量的值存入另一个变量中,或者直接使用其值,如下所示。
以下是一个具体的示例场景,完整说明了我的困境。
$ USER1_DIR=./user1/stuff
$ USER2_DIR=./user2/stuff
$ USER3_DIR=./user3/stuff

#User will be taken as input, for now assuming user is USER1 
$ USER="USER1"
$ DIR=${USER}_DIR

$ echo $DIR
>> USER1_DIR

$ DIR=${${USER}_DIR}
>> -bash: ${${USER}_DIR}: bad substitution

挑战 1:

当输入为 USER1 时,获取 DIR 值为 ./user1/stuff

或者

当输入为 USER1 时,获取输出值为 ./user1/stuff

完成挑战 1 后,需要像下面这样向用户目录中添加一些内容:


所需的输出如下所示


$ echo "Some stuff of user1" >> $DIR/${DOC}$NO

# Lets say DOC="DOC1" and NO="-346"
# So the content has to be added to ./user1/stuff/DOC1-346
# Assume that all Directories exists

请注意,上述代码将成为bash脚本中的一个函数的一部分,并且仅在Linux服务器上执行。

注:我不知道如何称呼变量DIR,因此使用了术语“嵌套”变量。如果您知道它被称为什么,请告诉我,非常感谢任何见解。:)


1
你需要的是所谓的间接变量扩展(用于查找)或赋值(用于修改)。请参阅[BashFAQ#6](http://mywiki.wooledge.org/BashFAQ/006)。顺便说一句,全大写的名称用于具有对操作系统或系统有意义的变量 - 使用小写名称来避免错误地覆盖它们。请参阅相关的POSIX规范@ http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html;第四段讲述了命名约定(在阅读时,请记住设置常规shell变量将覆盖任何同名的环境变量)。 - Charles Duffy
@Charles,感谢您的见解。我会记在心里的。 - Hemanth
1个回答

9
您可以使用eval变量间接引用${!...}引用变量declare -n
以下将使用小写变量名,因为按照惯例,大写变量名是特殊的。特别是覆盖$USER是不好的,因为该变量通常包含您的用户名(未显式设置)。对于以下代码片段,请假设以下变量:
user1_dir=./user1/stuff
user=user1

Eval

eval "echo \${${user}_dir}"
# prints `./user1/stuff`

Eval是bash内置命令,它会执行其参数,就像在bash中输入一样。这里使用eval调用参数echo "${user1_dir}"

使用eval被认为是不良实践,请参见此问题

变量间接引用

当将变量var1的名称存储在另一个变量var2中时,可以使用间接引用${!var2}来获取var1的值。

userdir="${user}_dir"
echo "${!userdir}"
# prints `./user1/stuff`

引用变量

在bash中,除了每次都使用间接寻址,您还可以声明一个引用变量:

declare -n myref="${user}_dir"

参考文献可以类比变量间接引用,但不需要编写!
echo "$myref"
# prints `./user1/stuff`

替代方案

使用(关联)数组可能会使您的脚本更加简单。数组是存储多个值的变量。可以使用索引访问单个值。普通数组使用自然数作为索引。关联数组使用任意字符串作为索引。

(普通)数组

# Create an array with three entries
myarray=(./user1/stuff ./user2/stuff ./user3/stuff)

# Get the first entry
echo "${myarray[0]}"

# Get the *n*-th entry
n=2
echo "${myarray[$n]}"

关联数组

声明一个包含三个元素的关联数组

# Create an associative array with three entries
declare -A myarray
myarray[user1]=./user1/stuff
myarray[user2]=./user2/stuff
myarray[user3]=./user3/stuff

# Get a fixed entry
echo "${myarray[user1]}"

# Get a variable entry
user=user1
echo "${myarray[$user]}"

1
花费了相当多的精力来构建一个广泛且正确的答案,以回答一个明显的重复问题。我不知道是要批评回答这个问题的决定,还是对那个答案的质量感到印象深刻。 :) - Charles Duffy
@Socowi,感谢您的回答。无言以对。这是我在这里看到的最好的答案之一。再次感谢.. :) - Hemanth
你能详细说明一下变量间接引用吗?链接打不开。 - konyak
@konyak 看起来链接的答案已被删除。我为间接性添加了自己的解释。希望这是你需要的。 - Socowi
好的,那很完美,谢谢! - konyak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接