如何在 Terraform local-exec 命令行中转义特殊字符

How to escape special characters in Terraform local-exec command line

我有以下地形:

resource "null_resource" "cognito_user_pool_client_id" {

 triggers  =  { always_run = "${timestamp()}" }
 provisioner "local-exec" {
  command = "aws cognito-idp list-user-pool-clients --user-pool-id  ${aws_cognito_user_pool.main.id} --region ${var.region} | grep -o '"ClientId": "[^"]*' | grep -o '[^"]*$' > ${path.module}/cognito_app_client.txt"

  depends_on = ["aws_cognito_user_pool_domain.main"]
}

我试图从 cognito 中的用户池中获取应用程序客户端 ID。无论如何,这条线因地形而失败:

Error: Invalid character

  on kibana_cognito.tf line 163, in resource "null_resource" "cognito_user_pool_client_id":
 163:   command = "aws cognito-idp list-user-pool-clients --user-pool-id  ${aws_cognito_user_pool.main.id} --region ${var.region} | grep -o '"ClientId": "[^"]*' | grep -o '[^"]*$' > ${path.module}/cognito_app_client.txt"

This character is not used within the language.


Error: Invalid character

  on kibana_cognito.tf line 163, in resource "null_resource" "cognito_user_pool_client_id":
 163:   command = "aws cognito-idp list-user-pool-clients --user-pool-id  ${aws_cognito_user_pool.main.id} --region ${var.region} | grep -o '"ClientId": "[^"]*' | grep -o '[^"]*$' > ${path.module}/cognito_app_client.txt"

Single quotes are not valid. Use double quotes (") to enclose strings.


Error: Invalid character

  on kibana_cognito.tf line 163, in resource "null_resource" "cognito_user_pool_client_id":
 163:   command = "aws cognito-idp list-user-pool-clients --user-pool-id  ${aws_cognito_user_pool.main.id} --region ${var.region} | grep -o '"ClientId": "[^"]*' | grep -o '[^"]*$' > ${path.module}/cognito_app_client.txt"

This character is not used within the language.

这适用于 aws cli :

(venv) ➜  virginia git:(master) ✗ aws cognito-idp list-user-pool-clients --user-pool-id  123456 --region us-east-1 | grep -o '"ClientId": "[^"]*' | grep -o '[^"]*$'
dsewe24dwr2e

如何在 terraform 中实现此功能?

这里有几种不同的“语言”需要处理,每种语言都可能需要进行一些转义以包含其中的语言,但是由于您特别询问了 Terraform,我将重点关注第一层转义,以确保 shell 看到您希望它看到的字符串。

这部分 Terraform 语言语法的相关文档是 Strings and Templates,其中讨论了 Terraform 语言中的两种不同类型的字符串以及它们各自提供的转义类型。


您当前使用的是 quoted string,因此您需要同时处理引用字符串转义 模板转义。您想要的字符串仅与引号转义的字符串交互,因为它包含一些您希望由 shell 而不是 Terraform 处理的文字引号字符 ",因此您可以将它们转义为 \" 就像文档建议的那样:

    command = "aws cognito-idp list-user-pool-clients --user-pool-id  ${aws_cognito_user_pool.main.id} --region ${var.region} | grep -o '\"ClientId\": \"[^\"]*' | grep -o '[^\"]*$' > ${path.module}/cognito_app_client.txt"

为了完整起见,我还要说 Unix shells 通常也支持 ${NAME} 语法作为 $NAME 的替代方法,在后者会产生歧义的情况下。 ${NAME} 与 Terraform 的模板语法冲突,因此如果您想在 shell 命令中包含像 that 这样的序列,那么您需要将其转义,如图所示在文档的第二个 table 中,改为写 $${NAME}


如果您阅读有关 heredoc strings 的下一节,您会发现它们的一个好处是它们没有用引号分隔,因此内容不会被解释为反斜杠转义序列,因此您可以按字面意思写引号和其他特殊字符:

    command = <<-EOT
      aws cognito-idp list-user-pool-clients --user-pool-id  ${aws_cognito_user_pool.main.id} --region ${var.region} | grep -o '"ClientId": "[^"]*' | grep -o '[^"]*$' > ${path.module}/cognito_app_client.txt
    EOT

Terraform 确实 仍然在此处解释模板序列 ${ ... }%{ ... },所以如果您有文字 ${NAME} 序列用于 shell 在这种情况下,您仍然需要将它们写成 $${NAME},但是您 不再 需要转义引号,因为这种类型的字符串由一个更长的、用户指定的标记 EOT,允许将内部引号视为文字。

使用 heredoc 字符串的另一个优点是您可以将命令拆分为多行,这可能更易于阅读:

    command = <<-EOT
      aws cognito-idp list-user-pool-clients --user-pool-id  ${aws_cognito_user_pool.main.id} --region ${var.region} \
        | grep -o '"ClientId": "[^"]*' | grep -o '[^"]*$' > ${path.module}/cognito_app_client.txt
    EOT

请注意,Unix shells 通常需要使用 \ 转义换行符以避免将其解释为两个单独的命令,因此我将其包含在上面的示例中,但从 Terraform 的角度来看,这只是模板扩展完成后要传递给 shell 的两行字符串。