2019-12-18 12:16:10 -05:00
|
|
|
|
---
|
2020-03-18 18:46:47 -04:00
|
|
|
|
layout: docs
|
|
|
|
|
page_title: Expressions - Configuration Language
|
2020-03-24 19:48:37 -04:00
|
|
|
|
sidebar_title: 'Expressions'
|
2019-12-18 12:16:10 -05:00
|
|
|
|
sidebar_current: configuration-expressions
|
|
|
|
|
description: |-
|
|
|
|
|
HCL allows the use of expressions to access data exported
|
2020-02-20 04:51:34 -05:00
|
|
|
|
by sources and to transform and combine that data to produce other values.
|
2019-12-18 12:16:10 -05:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# Expressions
|
|
|
|
|
|
|
|
|
|
_Expressions_ are used to refer to or compute values within a configuration.
|
|
|
|
|
The simplest expressions are just literal values, like `"hello"` or `5`, but
|
|
|
|
|
HCL also allows more complex expressions such as references to data exported by
|
2020-02-20 04:51:34 -05:00
|
|
|
|
sources, arithmetic, conditional evaluation, and a number of built-in
|
2019-12-18 12:16:10 -05:00
|
|
|
|
functions.
|
|
|
|
|
|
|
|
|
|
Expressions can be used in a number of places in HCL, but some contexts limit
|
|
|
|
|
which expression constructs are allowed, such as requiring a literal value of a
|
|
|
|
|
particular type or forbidding. Each language feature's documentation describes
|
|
|
|
|
any restrictions it places on expressions.
|
|
|
|
|
|
|
|
|
|
The rest of this page describes all of the features of Packer's
|
|
|
|
|
expression syntax.
|
|
|
|
|
|
|
|
|
|
## Types and Values
|
|
|
|
|
|
|
|
|
|
The result of an expression is a _value_. All values have a _type_, which
|
|
|
|
|
dictates where that value can be used and what transformations can be
|
|
|
|
|
applied to it.
|
|
|
|
|
|
|
|
|
|
HCL uses the following types for its values:
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `string`: a sequence of Unicode characters representing some text, like
|
2019-12-18 12:16:10 -05:00
|
|
|
|
`"hello"`.
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `number`: a numeric value. The `number` type can represent both whole
|
2019-12-18 12:16:10 -05:00
|
|
|
|
numbers like `15` and fractional values like `6.283185`.
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `bool`: either `true` or `false`. `bool` values can be used in conditional
|
2019-12-18 12:16:10 -05:00
|
|
|
|
logic.
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `list` (or `tuple`): a sequence of values, like
|
2019-12-18 12:16:10 -05:00
|
|
|
|
`["us-west-1a", "us-west-1c"]`. Elements in a list or tuple are identified by
|
|
|
|
|
consecutive whole numbers, starting with zero.
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `map` (or `object`): a group of values identified by named labels, like
|
2019-12-18 12:16:10 -05:00
|
|
|
|
`{name = "Mabel", age = 52}`.
|
|
|
|
|
|
|
|
|
|
Strings, numbers, and bools are sometimes called _primitive types._
|
|
|
|
|
Lists/tuples and maps/objects are sometimes called _complex types,_ _structural
|
|
|
|
|
types,_ or _collection types._
|
|
|
|
|
|
|
|
|
|
Finally, there is one special value that has _no_ type:
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `null`: a value that represents _absence_ or _omission._ If you set an
|
2019-12-18 12:16:10 -05:00
|
|
|
|
argument of a source or module to `null`, Packer behaves as though you
|
|
|
|
|
had completely omitted it — it will use the argument's default value if it has
|
|
|
|
|
one, or raise an error if the argument is mandatory. `null` is most useful in
|
|
|
|
|
conditional expressions, so you can dynamically omit an argument if a
|
|
|
|
|
condition isn't met.
|
|
|
|
|
|
|
|
|
|
### Advanced Type Details
|
|
|
|
|
|
|
|
|
|
In most situations, lists and tuples behave identically, as do maps and objects.
|
|
|
|
|
Whenever the distinction isn't relevant, the Packer documentation uses each
|
|
|
|
|
pair of terms interchangeably (with a historical preference for "list" and
|
|
|
|
|
"map").
|
|
|
|
|
|
|
|
|
|
However, module authors and provider developers should understand the
|
|
|
|
|
differences between these similar types (and the related `set` type), since they
|
|
|
|
|
offer different ways to restrict the allowed values for input variables and
|
|
|
|
|
source arguments.
|
|
|
|
|
|
|
|
|
|
### Type Conversion
|
|
|
|
|
|
2020-02-20 04:51:34 -05:00
|
|
|
|
Expressions are most often used to set values for arguments. In these cases,
|
|
|
|
|
the argument has an expected type and the given expression must produce a value
|
|
|
|
|
of that type.
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
|
|
|
|
Where possible, Packer automatically converts values from one type to
|
|
|
|
|
another in order to produce the expected type. If this isn't possible, Packer
|
|
|
|
|
will produce a type mismatch error and you must update the configuration with a
|
|
|
|
|
more suitable expression.
|
|
|
|
|
|
|
|
|
|
Packer automatically converts number and bool values to strings when needed.
|
|
|
|
|
It also converts strings to numbers or bools, as long as the string contains a
|
|
|
|
|
valid representation of a number or bool value.
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `true` converts to `"true"`, and vice-versa
|
|
|
|
|
- `false` converts to `"false"`, and vice-versa
|
|
|
|
|
- `15` converts to `"15"`, and vice-versa
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
|
|
|
|
## Literal Expressions
|
|
|
|
|
|
|
|
|
|
A _literal expression_ is an expression that directly represents a particular
|
|
|
|
|
constant value. Packer has a literal expression syntax for each of the value
|
|
|
|
|
types described above:
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- Strings are usually represented by a double-quoted sequence of Unicode
|
2019-12-18 12:16:10 -05:00
|
|
|
|
characters, `"like this"`. There is also a "heredoc" syntax for more complex
|
|
|
|
|
strings. String literals are the most complex kind of literal expression in
|
|
|
|
|
Packer, and have additional documentation on this page:
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- See [String Literals](#string-literals) below for information about escape
|
|
|
|
|
sequences and the heredoc syntax.
|
|
|
|
|
- See [String Templates](#string-templates) below for information about
|
|
|
|
|
interpolation and template directives.
|
|
|
|
|
- Numbers are represented by unquoted sequences of digits with or without a
|
2019-12-18 12:16:10 -05:00
|
|
|
|
decimal point, like `15` or `6.283185`.
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- Bools are represented by the unquoted symbols `true` and `false`.
|
|
|
|
|
- The null value is represented by the unquoted symbol `null`.
|
|
|
|
|
- Lists/tuples are represented by a pair of square brackets containing a
|
2019-12-18 12:16:10 -05:00
|
|
|
|
comma-separated sequence of values, like `["a", 15, true]`.
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
List literals can be split into multiple lines for readability, but always
|
|
|
|
|
require a comma between values. A comma after the final value is allowed,
|
|
|
|
|
but not required. Values in a list can be arbitrary expressions.
|
|
|
|
|
|
|
|
|
|
- Maps/objects are represented by a pair of curly braces containing a series of
|
2019-12-18 12:16:10 -05:00
|
|
|
|
`<KEY> = <VALUE>` pairs:
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
```hcl
|
|
|
|
|
{
|
|
|
|
|
name = "John"
|
|
|
|
|
age = 52
|
|
|
|
|
}
|
|
|
|
|
```
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
Key/value pairs can be separated by either a comma or a line break. Values
|
|
|
|
|
can be arbitrary expressions. Keys are strings; they can be left unquoted if
|
|
|
|
|
they are a valid [identifier](./syntax.html#identifiers), but must be quoted
|
|
|
|
|
otherwise. You can use a non-literal expression as a key by wrapping it in
|
|
|
|
|
parentheses, like `(var.business_unit_tag_name) = "SRE"`.
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
|
|
|
|
## References to Named Values
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
Packer makes one named values available.
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
|
|
|
|
The following named values are available:
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `source.<SOURCE TYPE>.<NAME>` is an object representing a
|
2019-12-18 12:16:10 -05:00
|
|
|
|
[source](./sources.html) of the given type
|
2019-12-19 10:23:30 -05:00
|
|
|
|
and name.
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
2020-02-20 04:51:34 -05:00
|
|
|
|
### Available Functions
|
|
|
|
|
|
|
|
|
|
For a full list of available functions, see [the function
|
|
|
|
|
reference](/docs/configuration/from-1.5/functions.html).
|
|
|
|
|
|
|
|
|
|
## `for` Expressions
|
|
|
|
|
|
|
|
|
|
A _`for` expression_ creates a complex type value by transforming
|
|
|
|
|
another complex type value. Each element in the input value
|
|
|
|
|
can correspond to either one or zero values in the result, and an arbitrary
|
|
|
|
|
expression can be used to transform each input element into an output element.
|
|
|
|
|
|
|
|
|
|
For example, if `var.list` is a list of strings, then the following expression
|
|
|
|
|
produces a list of strings with all-uppercase letters:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
[for s in var.list : upper(s)]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This `for` expression iterates over each element of `var.list`, and then
|
|
|
|
|
evaluates the expression `upper(s)` with `s` set to each respective element.
|
|
|
|
|
It then builds a new tuple value with all of the results of executing that
|
|
|
|
|
expression in the same order.
|
|
|
|
|
|
|
|
|
|
The type of brackets around the `for` expression decide what type of result
|
|
|
|
|
it produces. The above example uses `[` and `]`, which produces a tuple. If
|
|
|
|
|
`{` and `}` are used instead, the result is an object, and two result
|
|
|
|
|
expressions must be provided separated by the `=>` symbol:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
{for s in var.list : s => upper(s)}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This expression produces an object whose attributes are the original elements
|
|
|
|
|
from `var.list` and their corresponding values are the uppercase versions.
|
|
|
|
|
|
|
|
|
|
A `for` expression can also include an optional `if` clause to filter elements
|
|
|
|
|
from the source collection, which can produce a value with fewer elements than
|
|
|
|
|
the source:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
[for s in var.list : upper(s) if s != ""]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The source value can also be an object or map value, in which case two
|
|
|
|
|
temporary variable names can be provided to access the keys and values
|
|
|
|
|
respectively:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
[for k, v in var.map : length(k) + length(v)]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Finally, if the result type is an object (using `{` and `}` delimiters) then
|
|
|
|
|
the value result expression can be followed by the `...` symbol to group
|
|
|
|
|
together results that have a common key:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
{for s in var.list : substr(s, 0, 1) => s... if s != ""}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Splat Expressions
|
|
|
|
|
|
|
|
|
|
A _splat expression_ provides a more concise way to express a common operation
|
|
|
|
|
that could otherwise be performed with a `for` expression.
|
|
|
|
|
|
|
|
|
|
If `var.list` is a list of objects that all have an attribute `id`, then a list
|
|
|
|
|
of the ids could be produced with the following `for` expression:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
[for o in var.list : o.id]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is equivalent to the following _splat expression:_
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
var.list[*].id
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The special `[*]` symbol iterates over all of the elements of the list given to
|
|
|
|
|
its left and accesses from each one the attribute name given on its right. A
|
|
|
|
|
splat expression can also be used to access attributes and indexes from lists
|
|
|
|
|
of complex types by extending the sequence of operations to the right of the
|
|
|
|
|
symbol:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
var.list[*].interfaces[0].name
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The above expression is equivalent to the following `for` expression:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
[for o in var.list : o.interfaces[0].name]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Splat expressions are for lists only (and thus cannot be used [to reference
|
|
|
|
|
resources created with
|
|
|
|
|
`for_each`](/docs/configuration/resources.html#referring-to-instances-1), which
|
|
|
|
|
are represented as maps). However, if a splat expression is applied to a value
|
|
|
|
|
that is _not_ a list or tuple then the value is automatically wrapped in a
|
|
|
|
|
single-element list before processing.
|
|
|
|
|
|
|
|
|
|
For example, `var.single_object[*].id` is equivalent to
|
|
|
|
|
`[var.single_object][*].id`, or effectively `[var.single_object.id]`. This
|
|
|
|
|
behavior is not interesting in most cases, but it is particularly useful when
|
|
|
|
|
referring to resources that may or may not have `count` set, and thus may or
|
|
|
|
|
may not produce a tuple value:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
aws_instance.example[*].id
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The above will produce a list of ids whether `aws_instance.example` has `count`
|
|
|
|
|
set or not, avoiding the need to revise various other expressions in the
|
|
|
|
|
configuration when a particular resource switches to and from having `count`
|
|
|
|
|
set.
|
|
|
|
|
|
|
|
|
|
## `dynamic` blocks
|
|
|
|
|
|
|
|
|
|
Within top-level block constructs like sources, expressions can usually be used
|
|
|
|
|
only when assigning a value to an argument using the `name = expression` form.
|
|
|
|
|
This covers many uses, but some source types include repeatable _nested
|
|
|
|
|
blocks_ in their arguments, which do not accept expressions:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
source "amazon-ebs" "example" {
|
|
|
|
|
name = "pkr-test-name" # can use expressions here
|
|
|
|
|
|
|
|
|
|
tag {
|
|
|
|
|
# but the "tag" block is always a literal block
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
You can dynamically construct repeatable nested blocks like `tag` using a
|
|
|
|
|
special `dynamic` block type, which is supported anywhere, example:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
locals {
|
|
|
|
|
standard_tags = {
|
|
|
|
|
Component = "user-service"
|
|
|
|
|
Environment = "production"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
source "amazon-ebs" "example" {
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
tag {
|
|
|
|
|
key = "Name"
|
|
|
|
|
value = "example-asg-name"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dynamic "tag" {
|
|
|
|
|
for_each = local.standard_tags
|
|
|
|
|
|
|
|
|
|
content {
|
|
|
|
|
key = tag.key
|
|
|
|
|
value = tag.value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
A `dynamic` block acts much like a `for` expression, but produces nested blocks
|
|
|
|
|
instead of a complex typed value. It iterates over a given complex value, and
|
|
|
|
|
generates a nested block for each element of that complex value.
|
|
|
|
|
|
|
|
|
|
- The label of the dynamic block (`"tag"` in the example above) specifies
|
|
|
|
|
what kind of nested block to generate.
|
|
|
|
|
- The `for_each` argument provides the complex value to iterate over.
|
|
|
|
|
- The `iterator` argument (optional) sets the name of a temporary variable
|
|
|
|
|
that represents the current element of the complex value. If omitted, the name
|
|
|
|
|
of the variable defaults to the label of the `dynamic` block (`"tag"` in
|
|
|
|
|
the example above).
|
|
|
|
|
- The `labels` argument (optional) is a list of strings that specifies the block
|
|
|
|
|
labels, in order, to use for each generated block. You can use the temporary
|
|
|
|
|
iterator variable in this value.
|
|
|
|
|
- The nested `content` block defines the body of each generated block. You can
|
|
|
|
|
use the temporary iterator variable inside this block.
|
|
|
|
|
|
|
|
|
|
Since the `for_each` argument accepts any collection or structural value,
|
|
|
|
|
you can use a `for` expression or splat expression to transform an existing
|
|
|
|
|
collection.
|
|
|
|
|
|
|
|
|
|
The iterator object (`tag` in the example above) has two attributes:
|
|
|
|
|
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `key` is the map key or list element index for the current element. If the
|
2020-02-20 04:51:34 -05:00
|
|
|
|
`for_each` expression produces a _set_ value then `key` is identical to
|
|
|
|
|
`value` and should not be used.
|
2020-03-18 18:46:47 -04:00
|
|
|
|
- `value` is the value of the current element.
|
2020-02-20 04:51:34 -05:00
|
|
|
|
|
|
|
|
|
A `dynamic` block can only generate arguments that belong to the source type,
|
|
|
|
|
data source or provisioner being configured.
|
|
|
|
|
|
|
|
|
|
The `for_each` value must be a map or set with one element per desired nested
|
|
|
|
|
block. If you need to declare resource instances based on a nested data
|
|
|
|
|
structure or combinations of elements from multiple data structures you can use
|
|
|
|
|
expressions and functions to derive a suitable value. For some common examples
|
|
|
|
|
of such situations, see the
|
|
|
|
|
[`flatten`](/docs/configuration/from-1.5/functions/collection/flatten.html) and
|
|
|
|
|
[`setproduct`](/docs/configuration/from-1.5/functions/collection/setproduct.html)
|
|
|
|
|
functions.
|
|
|
|
|
|
|
|
|
|
### Best Practices for `dynamic` Blocks
|
|
|
|
|
|
|
|
|
|
Overuse of `dynamic` blocks can make configuration hard to read and maintain,
|
|
|
|
|
so we recommend using them only when you need to hide details in order to build
|
|
|
|
|
a clean user interface for a re-usable code. Always write nested blocks out
|
|
|
|
|
literally where possible.
|
|
|
|
|
|
2019-12-18 12:16:10 -05:00
|
|
|
|
## String Literals
|
|
|
|
|
|
|
|
|
|
HCL has two different syntaxes for string literals. The
|
|
|
|
|
most common is to delimit the string with quote characters (`"`), like
|
|
|
|
|
`"hello"`. In quoted strings, the backslash character serves as an escape
|
|
|
|
|
sequence, with the following characters selecting the escape behavior:
|
|
|
|
|
|
|
|
|
|
| Sequence | Replacement |
|
|
|
|
|
| ------------ | ----------------------------------------------------------------------------- |
|
|
|
|
|
| `\n` | Newline |
|
|
|
|
|
| `\r` | Carriage Return |
|
|
|
|
|
| `\t` | Tab |
|
|
|
|
|
| `\"` | Literal quote (without terminating the string) |
|
|
|
|
|
| `\\` | Literal backslash |
|
|
|
|
|
| `\uNNNN` | Unicode character from the basic multilingual plane (NNNN is four hex digits) |
|
|
|
|
|
| `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits) |
|
|
|
|
|
|
2019-12-19 10:23:30 -05:00
|
|
|
|
The alternative syntax for string literals is the so-called Here Documents or
|
|
|
|
|
"heredoc" style, inspired by Unix shell languages. This style allows multi-line
|
|
|
|
|
strings to be expressed more clearly by using a custom delimiter word on a line
|
|
|
|
|
of its own to close the string:
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
|
|
|
|
```hcl
|
2019-12-19 10:23:30 -05:00
|
|
|
|
<<EOF
|
2019-12-18 12:16:10 -05:00
|
|
|
|
hello
|
|
|
|
|
world
|
2019-12-19 10:23:30 -05:00
|
|
|
|
EOF
|
2019-12-18 12:16:10 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `<<` marker followed by any identifier at the end of a line introduces the
|
|
|
|
|
sequence. Packer then processes the following lines until it finds one that
|
|
|
|
|
consists entirely of the identifier given in the introducer. In the above
|
2019-12-19 10:23:30 -05:00
|
|
|
|
example, `EOF` is the identifier selected. Any identifier is allowed, but
|
2019-12-18 12:16:10 -05:00
|
|
|
|
conventionally this identifier is in all-uppercase and begins with `EO`, meaning
|
2019-12-19 10:23:30 -05:00
|
|
|
|
"end of". `EOF` in this case stands for "end of text".
|
2019-12-18 12:16:10 -05:00
|
|
|
|
|
|
|
|
|
The "heredoc" form shown above requires that the lines following be flush with
|
|
|
|
|
the left margin, which can be awkward when an expression is inside an indented
|
|
|
|
|
block:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
block {
|
2019-12-19 10:23:30 -05:00
|
|
|
|
value = <<EOF
|
2019-12-18 12:16:10 -05:00
|
|
|
|
hello
|
|
|
|
|
world
|
2019-12-19 10:23:30 -05:00
|
|
|
|
EOF
|
2019-12-18 12:16:10 -05:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
To improve on this, Packer also accepts an _indented_ heredoc string variant
|
|
|
|
|
that is introduced by the `<<-` sequence:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
block {
|
2019-12-19 10:23:30 -05:00
|
|
|
|
value = <<-EOF
|
2019-12-18 12:16:10 -05:00
|
|
|
|
hello
|
|
|
|
|
world
|
2019-12-19 10:23:30 -05:00
|
|
|
|
EOF
|
2019-12-18 12:16:10 -05:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In this case, Packer analyses the lines in the sequence to find the one
|
|
|
|
|
with the smallest number of leading spaces, and then trims that many spaces
|
|
|
|
|
from the beginning of all of the lines, leading to the following result:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
hello
|
|
|
|
|
world
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Backslash sequences are not interpreted in a heredoc string expression.
|
|
|
|
|
Instead, the backslash character is interpreted literally.
|
|
|
|
|
|
|
|
|
|
In both quoted and heredoc string expressions, Packer supports template
|
|
|
|
|
sequences that begin with `${` and `%{`. These are described in more detail
|
|
|
|
|
in the following section. To include these sequences _literally_ without
|
|
|
|
|
beginning a template sequence, double the leading character: `$${` or `%%{`.
|
|
|
|
|
|
|
|
|
|
## String Templates
|
|
|
|
|
|
|
|
|
|
Within quoted and heredoc string expressions, the sequences `${` and `%{` begin
|
|
|
|
|
_template sequences_. Templates let you directly embed expressions into a string
|
|
|
|
|
literal, to dynamically construct strings from other values.
|