Splunkでプログラムっぽいことをする

Splunk Answerの質問[How to breakdown TLV (Tag Length Value) format](https://answers.splunk.com/answers/793308/how-to-breakdown-tlv-tag-length-value-format.html)を無理やり解いた。

ちょっとモヤっとしたので、プログラムっぽくやってみたらできたので、新年一発目の投稿にしました。

#TLV
data in TLV format: 0104ABCD0203XYZ0502MQ

01 - Subfield 01
04 - Lenght of Subfield 01
ABCD - Content of Subfield 01

02 - Subfield 02
03 - Length of Subfield 02
XYZ - Content of Subfield 02

05 - Subfield 05
02 - Lenght of Subfield 05
MQ - Content of Subfield 05

ということらしいです。
#はじめの回答
```Splunk:TLVdecode.SPL
 | makeresults 
 | eval _raw="0209MDJXMNZOF0306852024060205
 0115300013698746230030658051404101319580514050201060214
 0115380013698554359030655053704101319550537060205
 0209MDSHRC6H60306851854050215060204
 0209MDSIU39OS0306320261060205
 0209MPGHON2H60306361705050206060262
 0115580013700140787030632036504101319320365060205
 0115300013699266920030673054204101319730542060205
 0115300013698579543030655264604101319552646060205"
 | makemv delim="
 " _raw
 | stats count by _raw
 | table _raw
 | rename COMMENT as "this is sample you provide. from here, the logic"
 | rex field=_raw "^(?<fn_1>\d\d)(?<fl_1>\d\d)"
 | eval sub1=substr(ltrim(_raw,fn_1.fl_1),1,fl_1)
 | eval blob_1=fn_1.fl_1.sub1
 | eval blob_2=substr(_raw,len(blob_1)+1)
 | rex field=blob_2 "^(?<fn_2>\d\d)(?<fl_2>\d\d)"
 | eval sub2=substr(blob_2,5,fl_2)
 | eval blob_2=fn_2.fl_2.sub2
 | eval blob_3=substr(_raw,len(blob_1.blob_2)+1)
 | rex field=blob_3 "^(?<fn_3>\d\d)(?<fl_3>\d\d)"
 | eval sub3=substr(blob_3,5,fl_3)
 | eval blob_3=fn_3.fl_3.sub3
 | eval blob_4=substr(_raw,len(blob_1.blob_2.blob_3)+1)
 | rex field=blob_4 "^(?<fn_4>\d\d)(?<fl_4>\d\d)"
 | eval sub4=substr(blob_4,5,fl_4)
 | eval blob_4=fn_4.fl_4.sub4
 | eval blob_5=substr(_raw,len(blob_1.blob_2.blob_3.blob_4)+1)
 | rex field=blob_5 "^(?<fn_5>\d\d)(?<fl_5>\d\d)"
 | eval sub5=substr(blob_5,5,fl_5)
 | eval blob_5=fn_5.fl_5.sub5
 | foreach fn_*
     [eval {<<FIELD>>} = sub<<MATCHSTR>>]
 | fields 0*
 | rename * as Subfield_*
```
自分でもよくやったなというくらい繰り返してる。
デバッグしながらやったので、これはこれでありでした。
最初は`ltrim`を使用してたんだけど、文字列が長いとうまく切り出せなかったりしたので諦め。
`substr`の繰り返しになったのは、他のコマンドできっていったら最後`05`が`5`になったりして、うまくいかなくなりました。なんでだろ　:question: 
#プログラムっぽく
```TLVlikeProgram.SPL
| makeresults 
| eval _raw="0209MDJXMNZOF0306852024060205
 0115300013698746230030658051404101319580514050201060214
 0115380013698554359030655053704101319550537060205
 0209MDSHRC6H60306851854050215060204
 0209MDSIU39OS0306320261060205
 0209MPGHON2H60306361705050206060262
 0115580013700140787030632036504101319320365060205
 0115300013699266920030673054204101319730542060205
 0115300013698579543030655264604101319552646060205" 
| makemv delim="
 " _raw 
| stats count by _raw 
| table _raw 
| rename COMMENT as "this is sample you provide. from here, the logic" 
| eval blob_1=_raw, blob_2="",blob_3="",blob_4="",blob_5="",blob_6="",start=0 
| foreach blob_* 
    [| eval fn_<<MATCHSTR>>=substr(<<FIELD>>,1,2) 
    | eval fl_<<MATCHSTR>>=substr(<<FIELD>>,3,2) 
    | eval sub<<MATCHSTR>>=substr(<<FIELD>>,5,fl_<<MATCHSTR>>) 
    | eval <<FIELD>>=fn_<<MATCHSTR>>.fl_<<MATCHSTR>>.sub<<MATCHSTR>> 
    | eval start=start+len(<<FIELD>>) 
    | eval count=<<MATCHSTR>> + 1 
    | eval blob_{count}=substr(_raw,start+1)] 
| foreach fn_* 
    [ eval {<<FIELD>>} = sub<<MATCHSTR>>] 
| fields 0* 
| rename * as Subfield_*
```
`foreach`でループするために、最初に`eval`で変数を作っているところがプログラムっぽい。
あと、ループの中の `eval start=start+len(<<FIELD>>)` のところとかも、そのままカウンター処理してる。
`| eval blob_{count}=substr(_raw,start+1)`なんかは次のフィールドに移れないので、名前をこのように作っている。
うまくいってよかった :sweat:
#まとめ
意外とSplunkでループできるかもしれない。 他のプログラム言語の`for`の使い方がこのようにできるので。
でも、なんに使おう :question: