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

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

2021年06月02日2022年10月13日

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

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

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

行単位で抽出

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

sample
$ 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
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

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

sample
$ 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

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

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

# 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行づつ見るので、行数が多いと処理に時間が掛かります。
参考になれば幸いです!