With zsh
:
mood='I am $1 happy'
happy () {
printf '%s\n' ${(e)mood}
}
happy very
The e
parameter expansion flags causes all the parameter expansions, arithmetic expansions and command substitutions to be evaluated in the content of the variable (backslash in front of the $
or `
can be used to prevent them).
Another approach that avoids dangerous things like the e
or eval
is to use gettext
's envsubst
, where you can specify exactly what you want substituted:
mood='I am $HOWMUCH happy'
happy() {
HOWMUCH=$1 envsubst <<< "$mood"
}
happy very
Though <<<
is also a zsh extension, it is now supported by a few other shells including bash
.
Replace envsubst
with envsubst '$HOWMUCH'
if you want to make sure that only $HOWMUCH
(or ${HOWMOUCH}
) gets substituted.
With ksh93
or zsh
, you can also use:
mood='I am %1$s happy\n'
happy() {
printf "$mood" "$@"
}
In other printf
implementations that don't support the %1$s
to specify which argument to use, in this particular case, you can use %s
. If the format has %s %s
, the first %s
gets the first argument, the second the second argument. You can use %2$s %1$s
to reverse the order with ksh93
or zsh
. In other implementations, you could use this trick instead:
case $(locale language) in
(*English*) msg="I am in a %s %s%.0s%.0s\n"; mood=mood;;
(*French*) msg="Je suis d'une %.0s%s %s%.0s\n"; mood=humeur;;
esac
mood() {
printf "$msg" "$@" "$@"
}
mood formidable "$mood"
Which would print I'm in a formidable mood
to an English-speaking user and Je suis d'une humeur formidable
to a French-speaking user. We pass the arguments twice and use %.0s
(the string truncated to zero width) to discard the ones we don't want to be able to use those arguments in different orders.
eval
but your answer solves the problem. Accepted. – bone Sep 05 '18 at 08:25eval
ends up evaluatingecho i am $1 happy
where$1
is not quoted. You'd want:eval "echo \"$mood\""
. So we end up evaluatingecho "i am $1 happy"
instead. – Stéphane Chazelas Sep 05 '18 at 10:20