The HashiCorp Configuration Language (HCL) comes with many built-in functions, the major ones including:
- Numeric functions for working with the number type
- Collection functions for managing complex data structures
- Encoding functions for encoding and decoding data
- String functions for string manipulation
The string functions category contains many functions to manipulate strings in different ways. Two such functions are [.code]split[.code] and [.code]join[.code]. In this blog post, we will explore these two functions, how they work, and what they are used for.
Disclaimer: All use cases of Terraform [.code]join[.code] and [.code]split[.code] functions discussed here work similarly in OpenTofu, the open-source Terraform alternative. However, to keep it simple and familiar for DevOps engineers, we will refer to these as “Terraform split” and “Terraform join” throughout this blog post.
Terraform split Function
The [.code]split[.code] function is a built-in function that takes a string input and a separator that determines where the input string will be divided. The output is a list of strings.
Syntax of the Terraform split function
The syntax of the Terraform [.code]split[.code] function is:
split(separator, string)
The [.code]split[.code] function has two arguments:
- [.code]separator[.code] is what the input string should be split on
- [.code]string[.code] is the value that should be split into a list of strings
To show how the split function works, here is a basic example using the [.code]terraform console[.code] command for splitting a static string:
$ terraform console
> split(",", "value1,value2,value3,value4")
tolist([
"value1",
"value2",
"value3",
"value4",
])
The separator argument does not have to be a single character; it could be an arbitrary string:
$ terraform console
> split("---", "value1---value2---value3")
tolist([
"value1",
"value2",
"value3",
])
Use cases for the Terraform split function
The [.code]split[.code] function is used for a variety of use cases involving splitting strings.
A few of the most common use cases are:
- Parsing the value of an input variable from a string to an array, e.g., a comma-separated list of subnet names
- Extracting parts of a string identifier, e.g., an Amazon Resource Name (ARN) string
- Removing a part of a string value, e.g., a leading "https://"
Alternatives to the Terraform split function
There are a number of alternative built-in functions to the [.code]split[.code] function, depending on what your goal is.
If you want to remove parts of a string you can instead use the [.code]replace[.code] function:
$ terraform console
> replace(
"https://docs.env0.com/docs/getting-started",
"https://",
"")
"docs.env0.com/docs/getting-started"
The [.code]replace[.code] function is more intuitive for this specific use case compared to splitting strings at the substring you want to remove.
If you want to extract all subnet names from a comma-separated string you could use the [.code]regexall[.code] function together with the flatten function:
$ terraform console
> flatten(regexall("([a-z0-9-]+)", "subnet-1,subnet-2,subnet-3"))
[
"subnet-1",
"subnet-2",
"subnet-3",
]
Terraform split Examples
Let's see some examples to understand how to use this function.
Parsing values of input variables
Let's assume you have a variable in your Terraform configuration that expects a string of subnet names separated by commas. You want to use the subnet names to create AWS subnet resources for each name.
The variable is defined in your variables.tf file:
variable "subnet_names" {
type = string
default = "subnet-1,subnet-2,subnet-3"
}
Use a local value in your network.tf file to get the individual names of the subnets from the input variable with the [.code]split[.code] function:
locals {
subnet_names = split(",", var.subnet_names)
}
In the same file, define your AWS VPC resource and use the [.code]local.subnet_names[.code] value to create a number of subnet resources in the VPC:
resource "aws_vpc" "this" {
cidr_block = "10.100.10.0/24"
}
resource "aws_subnet" "all" {
count = length(local.subnet_names)
vpc_id = aws_vpc.this.id
# the rest of the attributes are omitted
}
Extracting parts of a string identifier
Resources that you create in Terraform using a given cloud provider have some identifier string in their respective cloud. For AWS, resources have an Amazon Resource Name (ARN).
An example of an ARN for an AWS EC2 virtual machine is:
arn:aws:ec2:eu-west-1:123456789012:instance/i-0fb379ac92f436969
An ARN is the concatenation of a few different strings to form a unique identifier for the resource. The ARN includes the service name (ec2), the AWS region (eu-west-1), the account ID (123456789012), and more. Each part is separated by a colon.
Sometimes you need to access one or more string values from an ARN to use elsewhere in your Terraform configuration. This is a great use case for [.code]split[.code] function.
You can use local values to extract the parts that you are interested in. An example of an AWS EC2 instance is this:
resource "aws_instance" "web" {
# arguments omitted for brevity
}
locals {
arn = split(":", aws_instance.web.arn)
region = local.arn[3] # eu-west-1
account_id = local.arn[4] # 123456789012
instance_id = local.arn[5] # instance/i-0fb379ac92f436969
}
Removing a part of a string value
You may have an input variable value, or an attribute of a resource or data source, that represents a web address. This string value often starts with "http://" or "https://". However, the place in your Terraform configuration where you want to use this value might expect a value without "http://" or "https://".
You can use the [.code]split[.code] function to remove unwanted parts of a string. Note that if you remove the leading part of a string, the return value of the [.code]split[.code] function will include an empty string as the first value, for example:
$ terraform console
> split("https://", "https://google.com")
tolist([
"",
"google.com",
])
You’ll need to take this into account in your Terraform configuration.
Here’s an example of taking a full URL and extracting parts of it:
locals {
full_url = "https://docs.env0.com/docs/getting-started"
# docs.env0.com/docs/getting-started
first = split("https://", local.full_url)[1]
# docs.env0.com
subdomain = split("/", local.first)[0]
}
Terraform join Function
The Terraform [.code]join[.code] function is a built-in function that performs the opposite job of the [.code]split[.code] function. The [.code]join[.code] function is used to combine a list of string values into a single string.
Syntax of the Terraform join function
The syntax of the [.code]join[.code] function in Terraform CLI is:
join(separator, list)
There are two arguments for the [.code]join[.code] function:
- [.code]separator[.code] is a string that will be inserted between each element in the list of string values
- [.code]list[.code] is the list of string values that should be joined together
The output will be a single string made up of the list of input strings, with the specified delimiter in between. You can combine values from different source objects: static strings, resource attributes, input variables, and more.
Let's use the [.code]terraform console[.code] command to show how the [.code]join[.code] function works. This is a basic example of joining a static list of strings, i.e., string concatenation:
$ terraform console
> join(",", ["value1", "value2", "value3", "value4"])
"value1,value2,value3,value4"
The separator argument does not have to be a single character; it could be any string value:
$ terraform console
> join("---", ["value1", "value2", "value3"])
"value1---value2---value3"
In fact, the separator could also be an empty string:
$ terraform console
> join("", ["value1", "value2", "value3"])
"value1value2value3"
Use cases of the Terraform join function
A few of the most common use cases for the [.code]join[.code] function:
- Build URL and file path strings
- Building resource identifiers
The general use case is to combine data from various sources into a single string.
Alternatives to the Terraform join function
The most common alternative to the [.code]join[.code] function is string interpolation –. this is when you include other values in a string using the [.code]${...}[.code] syntax.
A simple example of string interpolation in a local value is shown below:
variable "domain" {
type = string
default = "docs.env0.com"
}
variable "path" {
type = string
default = "docs/getting-started"
}
locals {
url = "https://${var.domain}/${var.path}" #
}
Another alternative to the [.code]join[.code] function is the built in function named [.code]format[.code]:
$ terraform console
> format("%s,%s,%s", "subnet-1", "subnet-2", "subnet-3")
"subnet-1,subnet-2,subnet-3"
The [.code]format[.code] function can do much of what the Terraform [.code]join[.code] function can do, but is not intended for the same use cases.
Terraform join Examples
Let's see some examples that illustrate how to use the Terraform [.code]join[.code] function.
Build URL and file path strings
If you need to combine multiple separate strings into a file path or URL the [.code]join[.code] function is useful. These strings could be input variables, local values, resource attributes, or static strings.
Let's assume you have a number of variables representing parts of a website URL that you need to combine to form a full URL:
variable "domain" {
type = string
default = "docs.env0.com"
}
variable "path" {
type = string
default = "docs/getting-started"
}
locals {
# note that it should be "https:/" with a single "/" due to the separator being a "/"
url = join("/", ["https:/", var.domain, var.path)
}
A similar use case is to build file paths. Here is an example of using the local provider to read an existing configuration file for an environment based on the value of an input variable:
variable "environment" {
type = string
validation {
condition = contains(["dev", "prod"], var.environment)
error_message = "Use an valid environment name"
}
}
data "local_file" "config" {
filename = join("/", [path.module, "config", "${var.environment}.conf"])
}
Building resource identifiers
In a similar manner to how you used the [.code]split[.code] function to split an ARN identifier into parts, it is common to also have to build an identifier from its parts. This is a common use case for the [.code]join[.code] function.
In AWS resources have ARNs, and in Azure each resource has a resource ID. The resource ID is a string presented in the following format:
/subscriptions/<guid>/resourceGroups/<name>/providers/<provider>/<type>/<name>
There are a few static strings and a few varying strings, depending on the type of resource that the ID is for.
It is common for you to have to build these resource IDs from parts, as shown in the following simple example:
variable "storage_account_name" {
type = string
}
data "azurerm_client_config" "current" {}
resource "azurerm_resource_group" "this" {
# arguments omitted for brevity
}
locals {
resource_id = join("/", [
"/subscriptions",
data.azurerm_client_config.current.subscription_id,
"resourceGroups",
azurerm_resource_group.this.name,
"providers",
"Microsoft.Storage",
"storageAccounts",
var.storage_account_name
])
}
Final Thoughts
It is easy to manipulate data in HCL using the many built-in functions.
String manipulation functions are among the most used functions. The [.code]split[.code] and [.code]join[.code] functions are heavily used for tasks that require splitting strings into separate parts or combining different strings into a single string.
A common use case for the [.code]join[.code] function is building URLs, file paths, and resource identifiers from static strings, input variables, local values and resources, and data source attributes.
A common use case for the [.code]split[.code] function is to divide URLs, file paths, or resource identifiers to get specific parts from these strings.
The [.code]split[.code] and [.code]join[.code] functions perform opposite tasks.
Frequently Asked Questions
Q. How do you join a variable and a string?
Create a list of all the different objects you want to join and pass it to the [.code]join[.code] function:
$ terraform console
> join(",", [var.subnet_eu_west_1a, var.subnet_eu_west_1b, "subnet-1"])
"subnet-eu-west-1a,subnet-eu-west-1b,subnet-1"
Q. How do you join two lists?
Join elements from two or more lists of strings by passing all the lists to the [.code]join[.code] function:
$ terraform join
> join(",", ["subnet-1", "subnet-2"], ["subnet-3", "subnet-4"])
"subnet-1,subnet-2,subnet-3,subnet-4"
Q. How do you split a string on a substring?
Use the [.code]split[.code] function to split a string on a specified separator substring:
$ terraform console
> split(",", "subnet-1,subnet-2,subnet-3")
tolist([
"subnet-1",
"subnet-2",
"subnet-3",
])