展开一个 bash 变量,但不展开它包含的变量

Expand a bash variable, but not the variables it contains

我需要能够将变量扩展为它声明字符串的确切内容,而不是像通常那样 bash 在其声明中扩展其他变量。

variable=word
var="this variable contains a $variable"

echo ????

我需要一个结果为:“this variable contains a $variable”的命令 ...而不是:“this variable contains a word

变量声明必须保持不变,因为它需要在所有其他情况下正常展开。所以我不能在声明中使用单引号。

你可以使用单引号:

variable=word
var='this variable contains a $variable'
echo var

您所要求的实际上是不可能的,因为在双引号内,$variable 在定义 时被该变量 的内容替换。
在您打印它时,扩展早就发生了(使用 set 可以看出)。

如果您根本无法更改定义,您唯一可以尝试的方法就是还原替换:

echo ${var/"$variable"/'$variable'}

这将替换字符串文字 $variable 当前包含的 $variable 的所有匹配项,因此在您的示例中,它将替换所有匹配项 word$variable ,无论是否以这种方式定义。
此外,正如 Jasper 正确指出的那样,这依赖于 $variable$var.

的定义和打印之间没有改变的事实

现在,如果您实际上可以更改定义,但只希望扩展仍然发生,则有多种选择:

  1. 定义时使用单引号,打印时eval

    var='this variable contains a $variable'
    # later
    eval "echo "'"'"$var"'"'    # -> this variable contains a word
    echo $var                   # -> this variable contains a $variable
    

    诚然,这很麻烦。
    另请注意,变量扩展发生在打印时而不是定义时(实际上,只是在任何时间 eval 运行)。

  2. 使用两个不同的变量。

    不用每次都写 eval "echo "'"'"$var"'"',您可以将其结果存储在一个变量中并使用它,对吗?

    var='this variable contains a $variable'
    varX="$(eval "echo "'"'"$var"'"')"
    # later
    echo $varX      # -> this variable contains a word
    echo $var       # -> this variable contains a $variable
    

    或者,当然只是复制 $var 的定义并将 ' 替换为 "... 但那很无聊。 :P

    此处扩展发生在定义$varX时。

  3. 使用数组而不是两个不同的变量。

    这真的很有趣,因为对于数组 $var 等于 ${var[0]},所以你可以做

    tmp='this variable contains a $variable'
    var=("$(eval "echo "'"'"$tmp"'"')" "$tmp")
    # later
    echo $var           # -> this variable contains a word
    echo ${var[1]}      # -> this variable contains a $variable
    

    这可能与您想要的最接近,但您仍然需要更改定义。

你也可以使用 sed

variable=word
var="this variable contains a $variable"
var=$(echo "${var}" | sed "s/${variable}/${variable}/g")