
私は純粋な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
これは[バッシュFAQ/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
各キーと値のペアを1つずつ処理し、次を実行することです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"!
このコードは、現在の環境を汚染するのを防ぐためにサブシェルの内側に配置できます。
(PS:env
元の投稿で動的ビルドパラメータが機能しない理由はまだ疑問に思っています。助けてくれてありがとう。)