我想使用某种带有纯 bash 的简约模板引擎并且envsubst
:
user@host:~$ env -i FOO=foo BAR="bar baz" envsubst '$FOO,$BAR' \
<<< 'Hello "$FOO" and "$BAR"!'
Hello "foo" and "bar baz"!
以上有效,但仅包含静态变量。
现在让我们假设环境变量是动态给出的,就像关联数组一样:
declare -A MY_ENV=([FOO]=foo [BAR]="bar baz")
解析数组键值对仅适用于没有空格的环境值(错误):
env -i \
$(for k in "${!MY_ENV[@]}"; do printf "%s=%s " $k "${MY_ENV[$k]}"; done) \
envsubst #...
尝试用引号(用 note '%s'
代替%s
)括起环境值也会出错:
env -i \
$(for k in "${!MY_ENV[@]}"; do printf "%s='%s' " $k "${MY_ENV[$k]}"; done) \
envsubst #...
输出set -x
:
原因::set -x
表明 的参数env
变成了一个巨大的字符串
+ env -i 'FOO='\''foo'\''' 'BAR='\''bar' 'baz'\''' envsubst #...
env: ‘baz'’: No such file or directory
我肯定错过了逃生课(再次……)。我如何重写最后一个示例才能正常工作?
答案1
这是[Bash常见问题解答/050]-- 您必须使用一个数组来确保每一"key=value"
对都被正确引用。
vars=()
for k in "${!MY_ENV[@]}"; do
vars+=( "$k=${MY_ENV[$k]}" )
done
env -i "${vars[@]}" envsubst '$FOO,$BAR' <<< 'Hello "$FOO" and "$BAR"!'
Hello "foo" and "bar baz"!
请注意,我没有注入任何额外的引号字符。
扩展到这样我们就不必对变量名称进行硬编码:
keys=( "${!MY_ENV[@]}" )
printf -v varnames ',%s' "${keys[@]/#/'$'}"
env -i "${vars[@]}" envsubst "${varnames#,}" <<< 'Hello "$FOO" and "$BAR"!'
# or without the `varnames` temp var
env -i "${vars[@]}" envsubst "$(IFS=,; echo "${keys[*]/#/'$'}")" <<< 'Hello "$FOO" and "$BAR"!'
答案2
解决方法是export
逐一处理每个键值对,然后执行envsubst
:
for k in "${!MY_ENV[@]}"; do export $k="${MY_ENV[$k]}"; done
envsubst '$FOO,$BAR' <<< 'Hello "$FOO" and "$BAR"!'
#Hello "foo" and "bar baz"!
该代码可以放置在子 shell 内,以防止污染当前环境。
(PS:仍然好奇,为什么env
在原始帖子中动态构建参数不起作用 - 任何帮助表示赞赏。)