跳至主要内容

字符串和模板

字符串字面量是 OpenTofu 中最复杂的一种字面量表达式,也是最常用的。

OpenTofu 支持带引号的语法和 "heredoc" 语法来表示字符串。这两种语法都支持模板序列,用于插入值和操作文本。

带引号的字符串

带引号的字符串是由一对双引号 (") 括起来的字符序列。

代码块
"hello"

转义序列

在带引号的字符串中,反斜杠字符充当转义序列,以下字符选择转义行为

序列替换
\n换行符
\r回车符
\t制表符
\"字面引号(不终止字符串)
\\字面反斜杠
\uNNNN基本多语言平面上的 Unicode 字符 (NNNN 是四个十六进制数字)
\UNNNNNNNN补充平面上的 Unicode 字符 (NNNNNNNN 是八个十六进制数字)

还有两个不使用反斜杠的特殊转义序列

序列替换
$${字面量 ${,不会开始插值序列。
%%{字面量 %{,不会开始模板指令序列。

Heredoc 字符串

OpenTofu 还支持受 Unix shell 语言启发的 "heredoc" 风格的字符串字面量,它允许更清晰地表达多行字符串。

代码块
<<EOT
hello
world
EOT

Heredoc 字符串由以下部分组成:

  • 一个开头序列,包含:
    • 一个 heredoc 标记 (<<<<- - 两个小于号,可选地带一个连字符用于缩进的 heredoc)
    • 一个您选择的定界符单词
    • 一个换行符
  • 字符串的内容,可以跨越任意数量的行
  • 您选择的定界符单词,单独占据一行(缩进的 heredoc 允许缩进)

<< 标记后跟任何标识符,出现在一行的末尾,将引入该序列。OpenTofu 然后处理接下来的行,直到找到一个完全由引入器中给定的标识符组成的行。

在上面的示例中,EOT 是选择的标识符。任何标识符都是允许的,但是按照惯例,该标识符使用全大写字母,并且以 EO 开头,表示 "end of"。在本例中,EOT 代表 "end of text"。

生成 JSON 或 YAML

不要使用 "heredoc" 字符串来生成 JSON 或 YAML。相反,请使用 jsonencode 函数yamlencode 函数,以便 OpenTofu 可以负责保证有效的 JSON 或 YAML 语法。

代码块
  example = jsonencode({
a = 1
b = "hello"
})

缩进的 Heredocs

标准的 heredoc 形式(如上所示)将所有空格字符都视为字面空格。如果您不希望每行都以空格开头,那么每行都必须与左边缘对齐,这对缩进块中的表达式来说可能很麻烦。

代码块
block {
value = <<EOT
hello
world
EOT
}

为了改进这一点,OpenTofu 还接受一种名为缩进的 heredoc 字符串变体,它由 <<- 序列引入。

代码块
block {
value = <<-EOT
hello
world
EOT
}

在这种情况下,OpenTofu 会分析序列中的行,找到开头空格最少的行,然后从所有行的开头删除这么多空格,从而产生以下结果。

代码块
hello
world

转义序列

反斜杠序列在 heredoc 字符串表达式中不会被解释为转义符。相反,反斜杠字符会被直接解释。

Heredocs 支持两个不使用反斜杠的特殊转义序列

序列替换
$${字面量 ${,不会开始插值序列。
%%{字面量 %{,不会开始模板指令序列。

字符串模板

在带引号的和 heredoc 字符串表达式中,${%{ 序列会开始模板序列。模板允许您将表达式直接嵌入到字符串字面量中,以动态地从其他值构建字符串。

插值

${ ... } 序列是插值,它会计算标记之间的表达式,如果需要则将结果转换为字符串,然后将其插入到最终的字符串中。

代码块
"Hello, ${var.name}!"

在上面的示例中,会访问名为 var.name 的对象,并将它的值插入到字符串中,从而产生类似 "Hello, Juan!" 的结果。

指令

%{ ... } 序列是指令,它允许根据条件生成结果,并迭代集合,类似于条件表达式和 for 表达式。

支持以下指令:

  • %{if <BOOL>}/%{else}/%{endif} 指令根据布尔表达式的值在两个模板之间进行选择。

    代码块
    "Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"

    可以省略 else 部分,在这种情况下,如果条件表达式返回 false,则结果为空字符串。

  • %{for <NAME> in <COLLECTION>} / %{endfor} 指令会迭代给定集合或结构化值中的元素,并针对每个元素评估给定的模板一次,并将结果拼接在一起。

    代码块
    <<EOT
    %{ for ip in aws_instance.example[*].private_ip }
    server ${ip}
    %{ endfor }
    EOT

    for 关键字后面的名称用作临时变量名称,然后可以在嵌套的模板中引用。

空格去除

为了允许模板指令为了可读性而格式化,而不会在结果中添加不需要的空格和换行符,所有模板序列都可以包含可选的 *剥离标记* (~),紧接在开始字符之后或结束之前。当存在剥离标记时,模板序列将消耗所有字面空白(空格和换行符),这些空白要么在序列之前(如果标记出现在开头),要么在序列之后(如果标记出现在结尾)。

代码块
<<EOT
%{ for ip in aws_instance.example[*].private_ip ~}
server ${ip}
%{ endfor ~}
EOT

在上面的示例中,每个指令后的换行符不包含在输出中,但server ${ip}序列后的换行符保留,导致每个元素只生成一行。

代码块
server 10.1.16.154
server 10.1.16.1
server 10.1.16.34

在使用模板指令时,我们建议始终使用“heredoc”字符串文字形式,然后将模板格式化成多行以提高可读性。引用的字符串文字通常只应包含插值序列。