.env ファイルの内容を JSON にサクッと展開したい
docker-compose などローカル実行用の .env
ファイルの内容を、ECS Task Definition の環境変数定義のような name/value を持つ JSON オブジェクトの形式にサクッと変換したいことがよくあると思います。
これは jq コマンド一発でサクッと実現可能です。想定するファイル形式と展開先のオブジェクトキーが固定値なので、専用のショートカットを定義してあげると捗ります。
入力想定の .env
ファイルは、例えば次のような形式です。key/value のペアは改行区切りで、key と value の区切り記号は =
です。
# .env
FOO=xxx
BAR=xxx
これを JSON に展開した後の期待値は以下です。
[
{
"name": "FOO",
"value": "xxx",
},
{
"name": "BAR",
"value": "xxx"
]
結論
以下の関数を ~/.zshrc
などに定義しておきましょう。第一引数に読み込むファイルを食わせるようにして使います。
function dotenv-to-json () {
filename=$1
grep -v '^\s*#' ${filename} |grep -v '^\s*$' | \
jq -R 'split("\n") | map(split("=")) | flatten | {"name": .[0], "value": .[1]}'
}
Gist: https://gist.github.com/hassaku63/a9b40cfbaf641ede229ef0a8edca3699
jq のフィルタ式
次のようなフィルタを使用します。 -R
は入力を JSON としてパースしないことを明示するオプションです。テキストを自前でパースして展開・整形しています。
$ jq -R 'split("\n") | map(split("=")) | flatten | {"name": .[0], "value": .[1]}'
これ単品でもそこそこ有用なので、これを ~/.zshrc
などにエイリアスとして仕込んでおきます。ここではエイリアスを jq-dotenv
としました。
# zshrc
alias jq-dotenv="jq -R 'split(\"\n\") | map(split(\"=\")) | flatten | {\"name\": .[0], \"value\": .[1]}'"
使ってみる
source やシェルの再起動などで設定ファイルを反映して、試してみましょう。
$ cat <<EOF> .env
FOO=xxx
BAR=xxx
EOF
$ cat .env | jq-dotenv
{
"name": "FOO",
"value": "xxx"
}
{
"name": "BAR",
"value": "xxx"
}
意図したような結果になりました。これで Task Definition にコピペする手間が省けますね。jq のフィルタは都度書くのも面倒な場合が多いので、地味に便利です。
改善: 入力ファイルのコメントと空行を対策する
上記の内容そのままだと、 .env
にコメント行や空行が入っている場合は意図した出力になりません。ただ、そこは jq-dotenv にパイプする手前で対策するのが良いでしょう。
grep でコメント行と空行を除去してあげれば良いです。
$ grep -v '^\s*#' filename |grep -v '^\s*$'
参考: https://qiita.com/notakaos/items/91d807f3151694e6c7a8
このコマンドも地味にタイプするのが面倒くさそうです。こちらもショートカットを作りましょう。
grep ごとひとまとめにして、関数定義にしてしまいます。
function dotenv-to-json () {
filename=$1
grep -v '^\s*#' ${filename} |grep -v '^\s*$' | \
jq -R 'split("\n") | map(split("=")) | flatten | {"name": .[0], "value": .[1]}'
}
実行してみます。
$ cat <<EOF> text
FOO=xxx
# ssss
BAR=xxx
EOF
$ dotenv-to-json text
{
"name": "FOO",
"value": "xxx"
}
{
"name": "BAR",
"value": "xxx"
}
これで、空行やコメントにも対応した .env
ファイルの JSON 変換がサクッとできるようになりました。
Discussion