macのzshで文字抽出に役立つコマンド集

2021年06月02日2021年06月05日

kongのlog、json形式だから jq 使って解析しようと思ったがエラー。

parse error: Invalid numeric literal at line 1, column 3112


その前準備として、1次集計したときにjsonデータのエスケープが外れたみたい。
元データは手元になかったので1次集計したときのデータから文字抽出したので、そのときに使ったコマンド集。

行単位で抽出


head


指定した行数まで抽出できる。

# サンプルデータ
echo "aaa\nbbb\nccc\nddd\neee\nfff\nggg"

aaa
bbb
ccc
ddd
eee
fff
ggg

# 1行目までを取得
echo "aaa\nbbb\nccc\nddd\neee\nfff\nggg" | head -n 1
aaa

# 2行目までを取得
echo "aaa\nbbb\nccc\nddd\neee\nfff\nggg" | head -n 2
aaa
bbb


sed


指定した行を抽出できる。

# 1行目を取得
echo "aaa\nbbb\nccc\nddd\neee\nfff\nggg" | sed -n 1p
aaa

# 2行目を取得
echo "aaa\nbbb\nccc\nddd\neee\nfff\nggg" | sed -n 2p
bbb


列単位で抽出


cut


指定した列を抽出することができる。

# サンプルデータ
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg"
aaa   bbb
ccc   ddd
eee   fff
ggg

# 1列目を取得
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg" | cut -f 1
aaa
ccc
eee
ggg

# 2列目を取得
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg" | cut -f 2
bbb
ddd
fff
ggg


組み合わせてあげると行と列を指定して取得することができます。

指定する行と列のデータを取得する。


# 2行目の2列目を取得
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg" | sed -n 2p | cut -f 2
ddd


パイプで渡してあげるだけなんですけどね。

条件に合った行を抽出する


awk 'match($0, /条件/)'


# サンプルデータ
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg\taaa\nbbb\tccc"
aaa	bbb
ccc	ddd
eee	fff
ggg	aaa
bbb	ccc

# aaaが含まれている行を抽出
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg\taaa\nbbb\tccc" | awk 'match($0, /aaa/)'
aaa	bbb
ggg	aaa

# cccが含まれている行を抽出
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg\taaa\nbbb\tccc" | awk 'match($0, /ccc/)'
ccc	ddd
bbb	ccc


スラッシュ / で囲ってある条件にマッチした行だけを抽出します。
ちなみに正規表現も使えます。

# aが1回以上2回まで連続してある行を抽出する
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg\taaa\nbbb\tccc" | awk 'match($0, /a{1,2}/)'
aaa	bbb
ggg	aaa


正規表現については、どこかで解説をしたいですね。
奥が深すぎるから。

条件にあった文字列を抽出する


awk 'match($0, /条件/) {print substr($0, RSTART, RLENGTH)}'


# aが1回以上3回まで連続してある文字列を抽出する
echo "aaa\tbbb\nccc\tddd\neee\tfff\nggg\taaa\nbbb\tccc" | awk 'match($0, /a{1,3}/){print substr($0, RSTART, RLENGTH)}'
aaa
aaa


まとめ


今回したかったことは目的のスクリプトはコレ

cat kong.log | while read line; do
  echo "$(echo $line | wc -c)" "\t" "$(echo $line | awk 'match($0, /"started_at":[0-9]{13,13}/) {print substr($0, RSTART, RLENGTH)}')";
done > kong_1.tsv


1列目に出力されたログのbyte数
tab
2列目に"started_at":0123456789012

それを1行づつ処理している感じです。
1行づつ見るので、行数が多いと処理に時間が掛かります。

参考になれば幸いです!