is there an escape character for envsubst?

BashShellEnvsubst

Bash 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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionquinnView Question on Stackoverflow
Solution 1 - BashchepnerView Answer on Stackoverflow
Solution 2 - BashiokanuonView Answer on Stackoverflow
Solution 3 - BashblueFastView Answer on Stackoverflow
Solution 4 - BashLech PawłaszekView Answer on Stackoverflow
Solution 5 - BashMalvineousView Answer on Stackoverflow
Solution 6 - BashaaronView Answer on Stackoverflow
Solution 7 - BashJames StevensView Answer on Stackoverflow
Solution 8 - BashBvdrHorstView Answer on Stackoverflow
Solution 9 - BashAkshayView Answer on Stackoverflow