取消引用串联变量名


12

我可以做到这一点,但是它需要对变量进行字符串处理然后再取消引用。有什么办法可以将其简化为更简单的陈述?

#!/bin/bash

FRUITS="BANANA APPLE ORANGE"

BANANA_COLOUR="Yellow"
APPLE_COLOUR="Green or Red"
ORANGE_COLOUR="Blue"

for fruit in $( echo $FRUITS ); do
    fruit_colour="${fruit}_COLOUR"
    echo $fruit is ${!fruit_colour}
done

我尝试了很多类似${!"${fruit}_COLOUR"}\$${fruit}_COLOUR和其他许多变体的方法,但是唯一有效的方法是使用字符串。


!语法是变量替换一个标志,基本上说“替代两次”。并没有改变${…}必须包含变量名的要求。因此,除非您使用其他方法(eval),否则您将避免使用包含名称的变量。
吉尔斯(Gilles)'所以

您也可以使用关联数组更干净地执行此操作。但是,它不是您问题的直接答案,因此只需将其添加为评论即可。
Patrick

Answers:


11

首先,您不需要$(echo $FRUITS)for语句中使用。使用just $FRUITS就足够了。然后,您可以使用取消循环中的其中一行eval

eval简单地告诉bash中进行第二次评估下面的语句(即一个超过其正常的评价)。在\$生存的第一次评估的$,然后会在下次评估将这段$作为变量名的开始,它解析为“黄色”,等等。

这样,您就不需要一个单独的步骤来制作临时字符串(我认为这是您问题的主要意图)。

for fruit in $FRUITS ;do
    eval echo $fruit is \$${fruit}_COLOUR
done

对于另一种方法,如Patrick在上面的评论中所提到的,您可以改用关联数组,其中元素的索引不必是整数。您可以使用字符串,例如某种水果的名称。这是一个使用bash的关联数组的示例:

# This declares an associative array (It unsets it if it already exists)
declare -A colour
colour['BANANA']="Yellow"
colour["APPLE"]="Green or Red"
colour[MARTIAN ORANGE]="Blue"

for fruit in BANANA APPLE "MARTIAN ORANGE" ;do 
    echo "$fruit" is "${colour[$fruit]}"
done

6

您可以使用bash-builtin eval来做到这一点:

#!/bin/bash
FRUITS="BANANA APPLE ORANGE"
BANANA_COLOUR="Yellow"
APPLE_COLOUR="Green or Red"
ORANGE_COLOUR="Blue"

for fruit in $( echo $FRUITS );
do
    fruit_colour=${fruit}_COLOUR
    eval echo $fruit is \$${fruit_colour}
done

注意反斜杠美元符号。基本上,“ eval”行会导致bash 替换为$fruit${fruit_color},然后eval在调用之前用于进行第二轮替换echo


1

您不需要评估声明。eval大多数语言都暗示您做错了事。

foo_var=10
bar_var=12

# Build a string with your var name of choice
chosen_prefix='foo'
var_name="${chosen_prefix}_var"

# Use bang to deference it
chossen_value=${!var_name}
echo "Chossen value: ${chossen_value}"

我认为使用它是更安全的,eval因为至少有人知道它很危险,${!var}而且危险性差不多bash(如果$chosen_prefix在攻击者的控制下,它同样是命令注入漏洞),并且很少有人知道。尝试var_name='a[$(uname>&2)0]' bash -c 'v=${!var_name}'。最好的方法是关联数组。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.