カテゴリー
Awkコマンドを使ってテキストからjsonを生成する実用例〜株価日足で利用する
※ 当ページには【広告/PR】を含む場合があります。
2020/06/11
2022/09/30
実験用のテキスト
日付、始値、高値、低値、終値、売買高
2020-04-22
19109.18
19137.95
18858.25
19137.95
1247290000
2020-04-21
19479.83
19529.06
19193.22
19280.78
1280090000
2020-04-20
19689.85
19784.38
19611.79
19669.12
1065420000
2020-04-17
19575.85
19922.07
19554.70
19897.26
1409050000
2020-04-16
19311.30
19362.17
19154.41
19290.20
1298590000
input.dat
$ cat << EOF > input.dat
2020-04-22
19109.18
19137.95
18858.25
19137.95
1247290000
2020-04-21
19479.83
19529.06
19193.22
19280.78
1280090000
2020-04-20
19689.85
19784.38
19611.79
19669.12
1065420000
2020-04-17
19575.85
19922.07
19554.70
19897.26
1409050000
2020-04-16
19311.30
19362.17
19154.41
19290.20
1298590000
EOF
目標のjsonファイル
[
{
"date": "2020-04-22",
"open": 19109.18,
"high": 19137.95,
"low": 18858.25,
"close": 19137.95,
"volume": 1247290000
},
{
"date": "2020-04-21",
"open": 19479.83,
"high": 19529.06,
"low": 19193.22,
"close": 19280.78,
"volume": 1280090000
},
{
"date": "2020-04-20",
"open": 19689.85,
"high": 19784.38,
"low": 19611.79,
"close": 19669.12,
"volume": 1065420000
},
{
"date": "2020-04-17",
"open": 19575.85,
"high": 19922.07,
"low": 19554.7,
"close": 19897.26,
"volume": 1409050000
},
{
"date": "2020-04-16",
"open": 19311.3,
"high": 19362.17,
"low": 19154.41,
"close": 19290.2,
"volume": 1298590000
}
]
BEGINブロックとENDブロック
BEGIN{...前処理...}{...テキストの中身の処理...}END{...後処理...}
BEGIN
END
$ cat input.dat | awk '
BEGIN{
conv_json = "[";
}
{
print NR "行目" $0
}
END{
conv_json = conv_json "]";
print conv_json
}
'
1行目
2行目2020-04-22
3行目19109.18
4行目19137.95
5行目18858.25
6行目19137.95
7行目1247290000
8行目
9行目2020-04-21
10行目19479.83
11行目19529.06
12行目19193.22
13行目19280.78
14行目1280090000
15行目
16行目2020-04-20
17行目19689.85
18行目19784.38
19行目19611.79
20行目19669.12
21行目1065420000
22行目
23行目2020-04-17
24行目19575.85
25行目19922.07
26行目19554.70
27行目19897.26
28行目1409050000
29行目
30行目2020-04-16
31行目19311.30
32行目19362.17
33行目19154.41
34行目19290.20
35行目1298590000
36行目
[]
[]
[
]
NRと$0
NR
$0
$1, $2, ..., $n, ...
$0
$1, $2, ...
テキスト部分の処理
$ cat input.dat | awk '
BEGIN{
conv_json = "[";
}
/[0-9]{4}-[0-9]{2}-[0-9]{2}/{
print "日付は" NR "行目" $0
}
/^[0-9\.]+$/{
print "指標値は" NR "行目" $0
}
NF == 0{
print "空行は" NR "行目" $0
}
END{
conv_json = conv_json "]";
print conv_json
}
'
空行は1行目
日付は2行目2020-04-22
指標値は3行目19109.18
指標値は4行目19137.95
指標値は5行目18858.25
指標値は6行目19137.95
指標値は7行目1247290000
空行は8行目
日付は9行目2020-04-21
指標値は10行目19479.83
指標値は11行目19529.06
指標値は12行目19193.22
指標値は13行目19280.78
指標値は14行目1280090000
空行は15行目
日付は16行目2020-04-20
指標値は17行目19689.85
指標値は18行目19784.38
指標値は19行目19611.79
指標値は20行目19669.12
指標値は21行目1065420000
空行は22行目
日付は23行目2020-04-17
指標値は24行目19575.85
指標値は25行目19922.07
指標値は26行目19554.70
指標値は27行目19897.26
指標値は28行目1409050000
空行は29行目
日付は30行目2020-04-16
指標値は31行目19311.30
指標値は32行目19362.17
指標値は33行目19154.41
指標値は34行目19290.20
指標値は35行目1298590000
空行は36行目
[]
{}
<行を限定する条件>{}
/[0-9]{4}-[0-9]{2}-[0-9]{2}/
/[0-9]+/
NF == 0
{}
条件を省略することの意味
<行を限定する条件>
BEGIN{...前処理...}{...テキストの中身の処理...}END{...後処理...}
正規表現で条件を指定する
/[0-9]{4}-[0-9]{2}-[0-9]{2}/
2020-04-19
GNU版AWK
BSD版AWK
\d
GNU版AWK
BSD版AWK
\d
[0-9]
/^[0-9\.]+$/
^
$
^...$
特定の条件で指定する
NR
NF
NF == 0
空行
テキストからJSONオブジェクトを抽出
#
$ cat input.dat | awk '
BEGIN{
s_pos = 0; #初期値がFalseやゼロの場合、明示な変数の初期化はなくても良い
conv_json = "[";
}
/[0-9]{4}-[0-9]{2}-[0-9]{2}/{
s_pos = NR; #日付の行に来たらオブジェクトの最初の行数として記録
if(NR == s_pos) {
date = "\"date\":\"" $0 "\""
}
}
/^[0-9\.]+$/{
if(NR == s_pos+1) {
open = "\"open\":" $0
}
if(NR == s_pos+2) {
high = "\"high\":" $0
}
if(NR == s_pos+3) {
low = "\"low\":" $0
}
if(NR == s_pos+4) {
closed = "\"close\":" $0
}
if(NR == s_pos+5) {
volume = "\"volume\":" $0
}
}
NF == 0{
if(NR == s_pos+6) {
#空行を読み込んだら記録した変数を元にJSONオブジェクトを作成
content = "{" date "," open "," high "," low "," closed "," volume "}";
#配列の末尾にオブジェクトを追加
conv_json = conv_json content ","
}
}
END{
sub(/,$/, "", conv_json); # 末尾の余分な","を排除
conv_json = conv_json "]";
print conv_json
}
'
[{"date":"2020-04-22","open":19109.18,"high":19137.95,"low":18858.25,"close":19137.95,"volume":1247290000},{"date":"2020-04-21","open":19479.83,"high":19529.06,"low":19193.22,"close":19280.78,"volume":1280090000},{"date":"2020-04-20","open":19689.85,"high":19784.38,"low":19611.79,"close":19669.12,"volume":1065420000},{"date":"2020-04-17","open":19575.85,"high":19922.07,"low":19554.70,"close":19897.26,"volume":1409050000},{"date":"2020-04-16","open":19311.30,"high":19362.17,"low":19154.41,"close":19290.20,"volume":1298590000}]
if文を使う
if(条件) {...} else if(条件) {...} else {...}
if(条件){...}
if(条件) {...} else {...}
&&
||
組み込み関数sub()
sub()
sub(<置換文字(正規表現で最初にマッチする文字)>, <置換後の文字>, <入力文字列>)
,
$ echo '{},{},{},' | awk '{sub(/,$/,"",$0);print $0}'
{},{},{}
一部のデータが壊れている場合の対応
$ cat input.dat | awk '
BEGIN{
s_pos = 0;
conv_json = "[";
}
/[0-9]{4}-[0-9]{2}-[0-9]{2}/{
s_pos = NR;
if(NR == s_pos) {
date = "\"date\":\"" $0 "\""
}
#各値の初期化(異常があった場合-1が返る)
open = "\"open\":-1"
high = "\"high\":-1"
low = "\"low\":-1"
closed = "\"close\":-1"
volume = "\"volume\":-1"
}
/^[0-9\.]+$/{
if(NR == s_pos+1) {
open = "\"open\":" $0
}
if(NR == s_pos+2) {
high = "\"high\":" $0
}
if(NR == s_pos+3) {
low = "\"low\":" $0
}
if(NR == s_pos+4) {
closed = "\"close\":" $0
}
if(NR == s_pos+5) {
volume = "\"volume\":" $0
}
}
NF == 0{
if(NR == s_pos+6) {
content = "{" date "," open "," high "," low "," closed "," volume "}";
conv_json = conv_json content ","
}
}
END{
sub(/,$/, "", conv_json);
conv_json = conv_json "]";
print conv_json
}
'
最終的なスクリプトとして完成させる
#!/bin/bash
DATA_DIR=./path/to/datafile/
cat ${DATA_DIR}input.dat | awk '
BEGIN{
s_pos = 0;
conv_json = "[";
}
/[0-9]{4}-[0-9]{2}-[0-9]{2}/{
s_pos = NR;
if(NR == s_pos) {
date = "\"date\":\"" $0 "\""
}
open = "\"open\":-1"
high = "\"high\":-1"
low = "\"low\":-1"
closed = "\"close\":-1"
volume = "\"volume\":-1"
}
/^[0-9\.]+$/{
if(NR == s_pos+1) {
open = "\"open\":" $0
}
if(NR == s_pos+2) {
high = "\"high\":" $0
}
if(NR == s_pos+3) {
low = "\"low\":" $0
}
if(NR == s_pos+4) {
closed = "\"close\":" $0
}
if(NR == s_pos+5) {
volume = "\"volume\":" $0
}
}
NF == 0{
if(NR == s_pos+6) {
content = "{" date "," open "," high "," low "," closed "," volume "}";
conv_json = conv_json content ","
}
}
END{
sub(/,$/, "", conv_json);
conv_json = conv_json "]";
print conv_json
}
' > ${DATA_DIR}output.json
./path/to/datafile/
まとめ
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー