Hi,
I am using Terraform v0.13.1. I am trying to use provisioner local-exec to run some shell commands on an EC2 instance:
provisioner "local-exec" {
command = <<EOF
AWS_PROFILE=test ssh centos@<EC2 instance ID> "filename=test && touch \$filename && mv \$filename \$\{filename//t/a\}"
EOF
}
I got the following error message after running terraform apply:
null_resource.test (local-exec): Executing: ["/bin/sh" "-c" " AWS_PROFILE=test ssh centos@<instance ID> \"filename=test && touch \\$filename && mv \\$filename \\$\\{filename//t/a\\}\"\n"]
null_resource.test (local-exec): mv: cannot move 'test' to '${filename//t/a}' : No such file or directory
Error: Error running command ' AWS_PROFILE=test ssh centos@<instance ID> "filename=test && touch \$filename && mv \$filename \$\{filename//t/a\}"
': exit status 1. Output: mv: cannot move 'test' to '${filename//t/a}' : No such file or directory
It looks like Terraform was able to parse $filename
variable after adding escape to the dollar sign. However, shell variables in brackets (${filename}
) are not parsed properly in my case even though I added escape to the dollar sign.
I also tried \$$
and %${
but neither worked. I am lost on this. Can someone please advise whether this is supported in Terraform and what I did wrong?
Thanks in advance!
Hi @zhuyuejinhrb,
It seems that this error message is coming from the shell rather than from Terraform. I think that’s because \$\{filename//t/a\}
doesn’t include any sequences Terraform considers to be significant: this is a “heredoc” string rather than a quoted string, so \
is not significant to Terraform here, and because you placed a \
between the $
and the {
Terraform doesn’t see that as a template interpolation sequence either. The result is that the full literal string \$\{filename//t/a\}
gets to your shell.
The shell then does it own parsing of that. I assume it’s treating the backslashes as escape sequences and so the \$\{
part becomes a literal ${
, which causes the result to not be a valid filename.
With all of that said, I think what you were intending to do here is have the shell see the sequence ${filename//t/a}
and thus treat it as a shell interpolation, and your question here is how to escape the ${
sequence so Terraform won’t interpret it as a template interpolation.
If so, the answer is to double up the initial marker character without including any backslashes. (Backslashes are, in the Terraform language, only significant in quoted strings.)
provisioner "local-exec" {
command = <<EOF
AWS_PROFILE=test ssh centos@<EC2 instance ID> "filename=test && touch $filename && mv $filename $${filename//t/a}"
EOF
}
A $${
or %%{
sequence is understood by Terraform as meaning a literal ${
or %{
, respectively.
Thanks a lot! @apparentlymart
I tried your code but shell doesn’t recognize even $filename. I did some testing and found that the commands are ran by bash -c “commands”. To make it to work, I need to escape the dollar signs in the code. After some experiment, this code worked for me:
provisioner "local-exec" {
interpreter = ["/bin/bash", "-c"]
command = <<EOF
AWS_PROFILE=test ssh centos@<instance ID> "filename=test && touch \$filename && mv \$filename \$${filename//t/a}"
EOF
}
Thank you very much for pointing out doubling up the initial marker!