nologyance.net

日々のアウトプット

「ymlをパースするシェルスクリプト」をコードリーディングする

シェルスクリプトでymlで書かれたconfigファイルを読み込む方法を探していたところ、とあるリポジトリにたどり着きました。 親切にテストコードまで置いてあるので問題なく使用できたのですが、

如何せん何をやってるのかが説明できない。 Shellってちゃんとやったことないんですよね。。。

正直、念入りにテストしたわけでもないので、バグが含まれている可能性もあるわけです。 まぁ、色んな人が試してisuueとかも起票されているので、自分で作るより数倍品質は良いはずですが。

とはいえ、短いコードですし、せっかくなのでコードリーディングをしてみようと思います。 吸収できそうなものは積極的に取り入れていく。

主役のコードはこちら

parse_yaml.sh

2行目

さっそくわからん。 文法的に関数っぽい、と思ったらやっぱり関数でした。 でも、Functionって書いてないぞ? ⇒省略可能なようです。

3行目

localってなんだろう?local変数? ⇒local変数を定義するコマンドでした。詳しくはこちら bash のビルトインコマンド “local” について

つまり、ここでは自身の第2引数をプレフィックスとして代入しているようです。

4行目

正規表現をsとwとfsに代入している様子。使われ方がわからないと解析が辛いので一旦後回し。 ちなみに\034はカンマを8進数で表現したものらしい。

5行目

sedコマンドで文字列処理 nオプションで処理対象以外は出力しない。 eオプションで複数のスクリプトを一度に実行できる。 |が区切り文字になっておりs|bfstr|afstr|pとして置換処理を行う。

先頭のsは正規表現を利用して置換するコマンド 末尾のpは表示を行うコマンド

^($s) 変数を展開すると ^(:space:*) となり、行頭のスペース0回以上繰り返し

($w)$s:$s 変数を展開すると ([a-zA-Z0-9_]):space:::space:* となり、文字列+スペース+:+スペース

(.*) なんでも

ただ文字列にマッチングするだけであれば、key:valueのkeyも同じような表現でよいはずですが、 あえて([a-zA-Z0-9_]*)で表現されているのは「:」がマッチしないようにするためですかね。

$|\1$fs\2$fs\3

おそらく()の正規表現にマッチしたもの+「,」で置換していると思われる。つまり「①,②,③」= 「スペース,key,value」となる・・・のか?

6行目

5行目からダブルクォーテーションが省かれた形。 なぜ省いたVerを用意する必要があるのかはわからず・・・ $1は処理対象のymlファイルですね。 パイプで後ろの処理にパス

7行目

awkコマンドで列処理 先ほどの「スペース,key,value」に対して処理を行うようです。

8行目

インデントの数を格納していると思われるがlength($1)/2が解読できず。 ymlファイル名.lengthを2で割っている・・?

9行目

vnameという配列のindent番目にプレフィックスを代入

10行目

vnameのi番目がindentよりも大きければ配列から削除 解読できず

11~13行目

$3.lengthを・・・

$3?

ここで間違いに気づきました。

awkコマンドで使われているのはparse_yaml()の引数ではなくsedから渡された「スペース,key,value」では?

というわけでもう一度awkの中身へ

8行目

スペースの数/2がインデントだとみなしているみたいですね。 スペースが2つ以外の場合もあると思うのですが何故だろう。

11~13行目

valueが空でなければプレフィックスを先頭に、項目+「_」を入れ子分繰り返して改行、かな? スペース.length/2はもしかすると最上位の項目に対して処理を行わないためのフラグなのかもしれない。

残念ながら完全解読には至りませんでしたが、理解は進んだ気がします。 またshellに詳しくなったらリベンジしよう。