notebook

都内でWEB系エンジニアやってます。

スクリプトや設定ファイルをテンプレート化して環境変数を埋め込むenvsubstコマンド

簡単なスクリプトや設定ファイルなど、環境変数を埋め込んたファイルを生成したいみたいなパターンのときにenvsubstコマンドが使えます

今まで知らなかったことがもったいない

ということでメモ残しておきます

インストール

gettextを入れると使えるようになる

  • yum
yum install -y gettext
  • apt
apt install -y gettext

help

envsubst --help

Usage: envsubst [OPTION] [SHELL-FORMAT]

Substitutes the values of environment variables.

Operation mode:
  -v, --variables             output the variables occurring in SHELL-FORMAT

Informative output:
  -h, --help                  display this help and exit
  -V, --version               output version information and exit

In normal operation mode, standard input is copied to standard output,
with references to environment variables of the form $VARIABLE or ${VARIABLE}
being replaced with the corresponding values.  If a SHELL-FORMAT is given,
only those environment variables that are referenced in SHELL-FORMAT are
substituted; otherwise all environment variables references occurring in
standard input are substituted.

When --variables is used, standard input is ignored, and the output consists
of the environment variables that are referenced in SHELL-FORMAT, one per line.

Report bugs to <bug-gnu-gettext@gnu.org>.

標準入力から$VARIABLEまたは${VARIABLE}という形式で参照される環境変数を読み込んで、対応する値に置き換えてから標準出力に出力します

echo '$USER' | envsubst
vagrant
$ cat config.template.yml
name: $USER

$ cat config.template.yml | envsubst
name: vagrant

リダイレクトすれば環境変数を含めたファイルを生成できますね

変数展開対象を指定する

たとえばJavaScriptだとテンプレートリテラルでの変数参照方法とかぶっているので意図せず空文字にされてしまうパターンがある

  • 試してみる
$ cat hoge.js
const directory = '$PWD';
const user = '$USER';
console.log(`${user}ユーザーで${directory}にいます`);
$ cat hoge.js | envsubst
const directory = '/home/vagrant/dotfiles';
const user = 'vagrant';
console.log(`ユーザーでにいます`);

${user}${directory}という環境変数がないため空白として処理されてしまっています

SHELL-FORMAT

こういう場合ヘルプにもあるように[SHELL-FORMAT]を指定してあげることで特定の環境変数のみ埋め込みます

展開対象の変数名をenvsubstコマンドの後に記述します

$ cat hoge.js | envsubst '$USER $PWD'
const directory = '/home/vagrant/dotfiles';
const user = 'vagrant';
console.log(`${user}ユーザーで${directory}にいます`);

複数ある場合は列挙するなりスペースで区切るなりすることで実現できるが第一引数という扱いらしいのでシングルクオートで囲ってあげる必要はあります

区切りのスペースはありでもなしでも問題なく埋め込んでくれます

これで求めている変換結果が返ってきました

  • 実行してみる

サンプルなので標準出力からそのまま実行してみます

$ cat hoge.js | envsubst '$USER$PWD' | node
vagrantユーザーで/home/vagrant/dotfilesにいます

バッチリですね

対象の確認

-vオプションで変換対象の変数を確認できます

$ envsubst --variables '$HOGE some text ${FUGA}'
HOGE
FUGA

ファイルの中身を渡せば対象の変数となる値を確認できますね

-vで複数行の指定は出来ないため1行に変換してやってみます

$ cat hoge.js
const directory = '$PWD';
const user = '$USER';
console.log(`${user}ユーザーで${directory}にいます`);
$ envsubst -v "$(cat hoge.js | sed  -z 's/\n/ /g')"
PWD
USER
user
directory

$PWD$USERのみ変換対象としたかいがuserdirectoryも対象として入ってしまっていますね

意図した文字列以外も対象に入ってしまうのでSHELL-FORMATの指定が必要そうです

おわり

ブックマークレットを作っていたところAPIキーが必要になりキーはGit管理化には置けないけど貼り付けるときは埋め込んでおきたいといった用途でした

他にも簡単なスクリプトや設定ファイルなどにも使えそうなので覚えておきます