is there an escape character for envsubst?
BashShellEnvsubstBash Problem Overview
Is there a way to prevent envsubst
from substituting a $VARIABLE
? For example, I would expect something like:
export THIS=THAT
echo "dont substitute \\\$THIS" | envsubst
and have it return
dont substitute $THIS
but instead I get
dont substitute \THAT
is there any escape character for doing this?
Bash Solutions
Solution 1 - Bash
If you give envsubst
a list of variables, it only substitutes those variables, ignoring other substitutions. I'm not exactly sure how it works, but something like the following seems to do what you want:
$ export THIS=THAT FOO=BAR
$ echo 'dont substitute $THIS but do substitute $FOO' | envsubst '$FOO'
dont substitute $THIS but do substitute BAR
Note that $THIS
is left alone, but $FOO
is replaced by BAR
.
Solution 2 - Bash
export DOLLAR='$'
export THIS=THAT
echo '${DOLLAR}THIS' | envsubst
Or more clear:
export THIS=THAT
echo '${DOLLAR}THIS' | DOLLAR='$' envsubst
Solution 3 - Bash
My workaround is as follows:
Original template:
$change_this
$dont_change_this
Editted template:
$change_this
§dont_change_this
Now you can process:
envsubst < $template | sed -e 's/§/$/g'
This relies on the character §
not occurring anywhere else on your template. You can use any other character.
Solution 4 - Bash
$ echo $SHELL
/bin/bash
$ echo \$SHELL
$SHELL
$ echo \$SHELL | envsubst
/bin/bash
$ echo \$\${q}SHELL | envsubst
$SHELL
So doing $$
allows you to add a $
character. Then just "substitute" non-existent variable (here I used ${q}
but can be something more meaningful like ${my_empty_variable}
and you'll end up with what you need.
Just as with the paragraph solution - you need something special - here... a non-existent variable, which I like a bit more than performing additional sed on templates.
Solution 5 - Bash
If there's only one or two variables you don't want to expand, you can sort of whitelist them by temporarily setting them to their own name, like this:
$ echo 'one $two three $four' | four='$four' envsubst
one three $four
Here, the $four
variable gets replaced with $four
, effectively leaving it unchanged.
Solution 6 - Bash
In my case I wanted to only escape vars that aren't already defined. To do so run:
envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')"
Solution 7 - Bash
Here's an alternative that I use, as it saves installing the entire gettext
package for just one program. I have this awk script, I call envtmpl
, it will swap any environment variable that looks like {{ENV-VAR}}
for the value of ENV-VAR
#! /usr/bin/awk -f
{ for (a in ENVIRON) gsub("{{" _ a _ "}}",ENVIRON[a]); print }
So
$ echo "My shell '{{SHELL}}' is cool" | envtmpl
My shell '/bin/bash' is cool
As you can see, if {{
& }}
aren't what you prefer, its really each to change and this script works fine with busybox
's awk
.
It's not going to be the world's fastest solution, but it's really easy to implement and I mostly run it to prepare config files, so speed is pretty irrelevant.
WARNING: The only major difference between this and envsubst
is that this will NOT alter variables where no value exists. That is {{HAS-NO-VALUE}}
will be left exactly as that, where as envsubst
will remove those (replace them with blank).
You can fix this by adding more code into the awk
, if you want.
Solution 8 - Bash
Another way to "escape" some environment variable substitution is to use default value assignment (or any other variable processing) as envsubst will not substitute these:
$ export two=2
$ echo 'one $two three ${four:-}' | envsubst
one 2 three ${four:-}
The fourth envvar is not substituted, while in its output the processing to use defaulkt value is still there. This does not matter though, as processing this line later on will still deliver nothing if the variable is not set and its value when set.
Solution 9 - Bash
The way I did it is
export DONT_CHANGE_THIS=\${DONT_CHANGE_THIS}
envsubst < some-template.yml > changed.yml
So it will try to replace ${var} with ${var} and as output, you will get ${var} printed as it is