envsubstを使ってテキストファイルをテンプレートエンジンとして使う

2023-05-07Bash,Docker,Kubernetes

はじめに

Kubernetes のマニフェストファイル内に環境変数を埋め込み、出力内容を動的に変更したい場合がありました。

kustomizehelm といったツールを利用することで Kubernetes のマニフェストファイルに変数を埋め込むことはできます。
しかし、そこまで大層な仕組みを導入するような手間を掛けたくありません。

sed を使う方法もありますが、可読性は低くなります。

そんな場合、 envsubst コマンドを利用することで実現できました。

テキストファイルをテンプレートエンジンのとして利用できるシンプルで便利なコマンドです。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

envsubst コマンドとは

envsubst コマンドを使うと,変数展開など「テンプレートエンジン」のような仕組みを実現できます。

準備

僕の環境 ( CentOS ) には最初にインストールされていなかったため、まずはインストールから行いました。

$ yum install -y gettext

$ which envsubst
/usr/bin/envsubst

Mac 環境の場合は Homebrew でインストールできます ( 僕の Mac には気がついたらインストールされていました ) 。
apt でもきっと用意にインストールできるでしょう。

バージョンを確認します。

$ envsubst --version
envsubst (GNU gettext-runtime) 0.19.8.1
Copyright (C) 2003-2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Bruno Haible.

envsubst コマンドでテキストファイルに変数を埋め込んで見る

早速使ってみましょう。

変数を埋め込んだテキストを用意します。

$ cat <<'EOF' >template.txt
${GREETING}, ${YOUR_NAME}!
${YOUR_NAME}'s HOME is ${HOME}.
EOF

# 内容を確認
$ cat template.txt
${GREETING}, ${YOUR_NAME}!
${YOUR_NAME}'s HOME is ${HOME}.

ここでは 3 つの変数をテキストファイル内に記載しています。

  • GREETING
  • YOUR_NAME
  • HOME

HOME は、ログインシェルで接続しているユーザのホームディレクトリを表す環境変数ですね。

# 僕は /root ユーザで今回の操作を行っています。
$ echo $HOME
/root

テキストファイルに対して変数を埋め込むには、 envsubst に対してファイルの内容をリダイレクトさせます。

$ envsubst < template.txt
, !
's HOME is /root.

なんとも悲しい結果になってしまいました。
${GREETING}${YOUR_NAME} の 2 つの記述が消えてしまいました。
${HOME} の記述は /root に置き換えられていますね。

原因は GREETINGYOUR_NAME の 2 つの変数を定義していなかったためです。

改めて変数を定義して再実行してみましょう。
ただし、変数は export する必要があることに注意してください。

$ export GREETING=Hello
$ export YOUR_NAME=genzouw

$ envsubst < template.txt
Hello, genzouw!
genzouw's HOME is /root.

変数の値を変更すれば正しく反映されます。

$ export GREETING=こんにちわ
$ export YOUR_NAME=root

こんにちわ, root!
root's HOME is /root.

${...} 形式で記述しているけど変数として展開してほしくない場合

もう一度先程のテンプレートファイルを見てみます。

$ cat template.txt
${GREETING}, ${YOUR_NAME}!
${YOUR_NAME}'s HOME is ${HOME}.

ここで、 ${GREETING}${YOUR_NAME} の部分ですが、変数を定義しておかないと envsubst 適用後は空白になってしまいます。
${GREETING}${YOUR_NAME} を「変数として展開してほしくない」という場合は、
変数として展開してほしい HOME だけを envsubst コマンドの引数に指定します

$ envsubst '${HOME}' < template.txt
${GREETING}, ${YOUR_NAME}!
${YOUR_NAME}'s HOME is /root.

引数はシングルクォーテーションで囲んで $XXX とする点に注意です。
GREETING も対象にする場合は以下のように指定します。

$ export GREETING=hello

$ envsubst '${HOME} ${GREETING}' < template.txt
hello, ${YOUR_NAME}!
${YOUR_NAME}'s HOME is /root.

ひとこと

便利そうですが、 ${...} または $... の記述がテキストファイル内に存在すると変数展開されてしまいます。
Nginx の設定ファイルや .htaccess のようなファイルには $ の記述がよく使われますし、気をつけないと意図しない変換が行われる点に注意が必要です。

2023-05-07Bash,Docker,Kubernetes