如何为命令动态设置环境变量?

如何为命令动态设置环境变量?

我想使用某种带有纯 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在原始帖子中动态构建参数不起作用 - 任何帮助表示赞赏。)

相关内容