Jakub Bochenski Jakub Bochenski - 25 days ago 7
Bash Question

Parameterized substitutions (${foo%bar}, ${foo-bar}, etc) without using eval

From

envsubst
man:


These substitutions are a subset of the substitutions that a shell
performs on unquoted and double-quoted strings. Other kinds of
substitutions done by a shell, such as ${variable-default} or
$(command-list) or `command-list`, are not performed by the
envsubst

program, due to security reasons.


I'd like to perform variable substitution a string, supporting constructs like
${variable-default}
or
${variable%suffix}
. I don't want to allow running commands.

Apparently it's not possible using
envsubst
, on the other hand
eval
has serious security implications.

Is there some other possibility than writing custom interpolation function?

Answer

bash 4.4 introduced a new type of parameter expansion which might do what you want. Namely, ${foo@P} expands the value of foo as if it were a prompt string, and a prompt string does undergo a round of expansion just prior to being displayed.

${parameter@operator}
    Parameter transformation.  The expansion is either a transforma-
    tion  of  the  value of parameter or information about parameter
    itself, depending on the value of operator.  Each operator is  a
    single letter:

    Q      The  expansion is a string that is the value of parameter
           quoted in a format that can be reused as input.
    E      The expansion is a string that is the value of  parameter
           with  backslash  escape  sequences  expanded  as with the
           $'...' quoting mechansim.
    P      The expansion is a string that is the result of expanding
           the value of parameter as if it were a prompt string (see
           PROMPTING below).
    A      The expansion is a string in the form  of  an  assignment
           statement  or  declare  command  that, if evaluated, will
           recreate parameter with its attributes and value.
    a      The expansion is a string consisting of flag values  rep-
           resenting parameter's attributes.

A quick example:

$ foo='${bar:-9}'
$ echo "$foo"
${bar:-9}
$ echo "${foo@P}"
9
$ bar=3
echo "${foo@P}"
3

It does, however, still allow running arbitrary commands via $(...):

$ foo='$(echo hi)'
$ echo "${foo@P}"
hi

Another caveat: it does, of course, also expand prompt escapes, so you may be more expansions than you expected if your string already contains some backslashes. There is some conflict between prompt escapes and escapes intended for echo -e.