a8m / envsubst

Environment variables substitution for Go
MIT License
768 stars 83 forks source link

Feature Request / Possible bug: Support nested variables enclosed by raw string #30

Open janosmiko opened 3 years ago

janosmiko commented 3 years ago

I have a weird issue where envsubst is not working as expected.

When I add only a single a default variable to the right side of the experssion it will work similarly as a default POSIX shell. But when I add additional text to the default it start to do some strange behaviour.

I'll provide some examples, I believe that will be the best description.

sh use case:

docker run --rm -it debian:buster-slim sh
# export VAR1="shouldevaluate"
# export EMPTY_VAR=""
# export MAIN_VAR="${EMPTY_VAR:-$VAR1}"
# echo $MAIN_VAR
shouldevaluate
#
#
# export MAIN_VAR="${EMPTY_VAR:-asdqwe$VAR1}"
# echo $MAIN_VAR
asdqweshouldevaluate
#
#
# export MAIN_VAR="${EMPTY_VAR:-asdqwe $VAR1 qweasd}"
# echo $MAIN_VAR
asdqwe shouldevaluate qweasd
#
#
# export MAIN_VAR="${EMPTY_VAR:-asdqwe${VAR1}qweasd}"
# echo $MAIN_VAR
asdqweshouldevaluateqweasd

And this happens when I try to use the same method in envsubst.

# cat test.template
name = ${EMPTY_VAR:-$VAR1}

name = ${EMPTY_VAR:-asdqwe$VAR1}

name = ${EMPTY_VAR:-asdqwe $VAR1 qweasd}

name = ${EMPTY_VAR:-asdqwe${VAR1}qweasd}
#
#
# envsubst < test.template
name = shouldevaluate

name = asdqwe$VAR1

name = asdqwe $VAR1 qweasd

name = asdqwe${VAR1qweasd}
graineri commented 3 years ago

Would it be possible to add this feature?

polarathene commented 1 year ago

Just chiming in with my own experience.

The README only shows support for ${VAR}, with any fallback value as $VAR..


#! /bin/bash

export LDAP_BIND_DN=nested_var
export SASLAUTHD_LDAP_FILTER=testing

# sed removes the lines with empty values:
/tmp/envsubst < /tmp/test.conf | sed '/^.*: $/d' > /tmp/saslauthd.conf

With /tmp/test.conf as input (stdin):

ldap_servers: ${SASLAUTHD_LDAP_SERVER:=${LDAP_SERVER_HOST}}
ldap_auth_method: ${SASLAUTHD_LDAP_AUTH_METHOD:=bind}
ldap_bind_dn: ${SASLAUTHD_LDAP_BIND_DN:=${LDAP_BIND_DN}}
ldap_bind_pw: ${SASLAUTHD_LDAP_PASSWORD:=${LDAP_BIND_PW}}
ldap_search_base: ${SASLAUTHD_LDAP_SEARCH_BASE:=${LDAP_SEARCH_BASE}}
ldap_filter: ${SASLAUTHD_LDAP_FILTER:=(&(mail=%u)(mailEnabled=TRUE))}

ldap_start_tls: ${SASLAUTHD_LDAP_START_TLS:=no}
ldap_tls_check_peer: ${SASLAUTHD_LDAP_TLS_CHECK_PEER:=no}
ldap_tls_cacert_file: ${SASLAUTHD_LDAP_TLS_CACERT_FILE}
ldap_tls_cacert_dir: ${SASLAUTHD_LDAP_TLS_CACERT_DIR}

ldap_referrals: yes
log_level: 10

Results in /tmp//saslauthd.conf output:

ldap_servers: }
ldap_auth_method: bind
ldap_bind_dn: }
ldap_bind_pw: }
ldap_search_base: }
ldap_filter: testing

ldap_start_tls: no
ldap_tls_check_peer: no

ldap_referrals: yes
log_level: 10

We can see that all values with a default using ${VAR} became }, even when one was set ${LDAP_BIND_DN} for ldap_bind_dn:.

This works fine if using $LDAP_BIND_DN (no nested braces used). Given the last output from other comments above (asdqwe${VAR1qweasd}), it seems that:

asdqwe${VAR1qweasd} also implies that the first } was removed, then everything to the left was treated as the fallback value, which if not starting as $ is not evaluated 🤷‍♂️ While if it is you get the output I experienced which'd fail to evaluate.