Search code examples
shellcommand-line-argumentsstring-interpolation

How to interpolate a string that was sent as an argument?


I have limited access to the filesystem, and I want to set up universal notification handler call like that:

notificator.sh "apples" "oranges" "There were $(1) and $(2) in the basket"

notificator.sh contents:

#!/bin/sh
echo $3

And get output looking like:

"There were apples and oranges in the basket"

Is it possible and how? I'd prefer if it was a builtin sh solution. I'm actually trying to send the result string ($3) as a message to the telegram bot via curl post param, but tried to simplify the situation.


Solution

  • With some changes to your $3, we can make this work easily.

    First, let's define $1, $2, and $3:

    $ set -- "apples" "oranges" 'There were ${one} and ${two} in the basket'
    

    Now, let's force substitutions into $3:

    $ one=$1 two=$2 envsubst <<<"$3"
    There were apples and oranges in the basket
    

    Notes:

    1. $(1) attempts to run a command named 1 and will likely generate an error even before your script runs. Use ${var} instead.

    2. To get this method to work, we needed to rename the variables in $3.

    3. envsubst is part of the GNU gettext-base package and should be available by default of Linux distributions.

    Hat tip to Charles Duffy.

    In script form

    Consider this script:

    $ cat script.sh
    #!/bin/sh
    echo "$3" | one=$1 two=$2 envsubst
    

    We can execute the above:

    $ sh script.sh "apples" "oranges" 'There were ${one} and ${two} in the basket'
    There were apples and oranges in the basket
    

    As an alternative (hat tip again to Charles Duffy), we can use a here-doc:

    $ cat script2.sh
    #!/bin/sh
    one=$1 two=$2 envsubst <<EOF
    $3
    EOF
    

    Running this version:

    $ sh script2.sh "apples" "oranges" 'There were ${one} and ${two} in the basket'
    There were apples and oranges in the basket
    

    Alternative

    The following script does not require envsubst:

    $ cat script3.sh
    #!/bin/sh
    echo "$3" | awk '{gsub(/\$\{1\}/, a); gsub(/\$\{2\}/, b)} 1' a=$1 b=$2
    

    Running this script with our arguments, we find:

    $ sh script3.sh "apples" "oranges" 'There were ${1} and ${2} in the basket'
    There were apples and oranges in the basket
    $ sh script3.sh "apples" "oranges" 'There were ${1} and ${2} in the basket'
    There were apples and oranges in the basket