あるプロジェクトで、環境変数が.env
ファイルに格納されており、その中の一つの環境変数が、独特のフォーマットで記述されており、それをパースする必要があった。
そのメモとしてブログを残しておく。
問題
.env
ファイルに格納された文字列がある。
FOO=BAR
SOME='{ aks_node_vm_size="Standard_L8s_v2", dns_prefix="staging-e", agent_count_min=1,agent_count_max=10, agent_count_enable_autoscale=true, kubernetes_version="1.14.7", cluster_name="some-aks", vnet_subnet_name="some-aks-subnet", gateway_name="some-gateway" }'
この状況で、cluster_name
の値だけを取得したい。
dotnenv ファイルを読み込んで環境変数にする
これは意外とややこしい。当初はgrep
を使ってやろうとしていたが、上記のような複雑な変数は上手く読めなかったりした。しかし簡単な方法があった。
set -o allexport;
source $TEST_ENV_FILE_PATH
set +o allexport;
ちなみに-o allexport
は全ての変数をexportする指定で、-a
でもよいようです。
ちなみに +o
の指定はオプションの無効化になります。つまり、AllExportを指定した状態でEnvファイルを読み込めばまずは、環境変数までもってこれます。
複雑な環境変数をパースする。
SOME='{ aks_node_vm_size="Standard_L8s_v2", dns_prefix="staging-engine", agent_count_min=1,agent_count_max=10, agent_count_enable_autoscale=true, kubernetes_version="1.14.7", cluster_name="some-aks", vnet_subnet_name="some-aks-subnet", gateway_name="some-gateway" }'
これのパースだが、最初はこんなコードを書いていた。できるねんけど、ダサさが漂っている。基本的にやってることは、IFSを変えて,
で分割して、
余計なダブルクオートや、変数名をカットという感じ。
#!/bin/bash
OLDIFS=$IFS
IFS=","
pattern="^cluster_name="
CLUSTER_NAME=""
for kv in $SOME
KEY_VALUE=$(echo $kv | xargs)
if [[ $KEY_VALUE =~ $pattern ]]; then
CLUSTER_NAME=$(echo $KEY_VALUE | sed 's/cluster_name=//')
fi
done
echo $CLUSTER_NAME
これを何とかワンライナーで出来ないかと思い、Sedを調査した。Sedの置換のコマンドを使っている。
cluster_name=の直後で、空白、もしくは,
ではない文字列をヒットさせる。 \( \)
は、ここで
ヒットした内容を後で参照できる。つまり、空白や,
が先ほどの文字列の区切りにでてくるので、次にそれがヒットするまでは
( )
の中の内容になる。.*
は任意の文字列にヒットする。この内容(つまり、cluster_name=以降の文字列)を、\1
つまり、
( )
の中でヒットした内容を置換する。つまりそれは、"some-aks" になるので、それのダブルクオートをxargsでとって終わり。
CLUSTER_NAME=$(echo $SOME | sed 's/.*cluster_name=\([^ ,]*\).*/\1/' | xargs)
echo $CLUSTER_NAME
xargs で、"" が取り除かれるのは、元々 xargsはデリミタで分割した文字を返すもの
xargsは、改行等で区切られた標準入力を読み込み、空白で区切られた1行の文字列へ加工し、それを引数として指定したコマンドへ渡して実行させる。
なので、デリミタが無い場合は、単純に、1行の文字列に加工するけど、""をストリップするのだろう。
部分抽出に関しては下記のブログを参考にしました。