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

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

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, /条件/)'

    # サンプルデータ\necho \"aaa\\tbbb\\nccc\\tddd\\neee\\tfff\\nggg\\taaa\\nbbb\\tccc\"\naaa\tbbb\nccc\tddd\neee\tfff\nggg\taaa\nbbb\tccc\n\n# aaaが含まれている行を抽出\necho \"aaa\\tbbb\\nccc\\tddd\\neee\\tfff\\nggg\\taaa\\nbbb\\tccc\" | awk 'match($0, /aaa/)'\naaa\tbbb\nggg\taaa\n\n# cccが含まれている行を抽出\necho \"aaa\\tbbb\\nccc\\tddd\\neee\\tfff\\nggg\\taaa\\nbbb\\tccc\" | awk 'match($0, /ccc/)'\nccc\tddd\nbbb\tccc

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

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

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

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

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

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

### まとめ

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

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

1列目に出力されたログのbyte数  
tab  
2列目に\"started_at\":0123456789012  
それを1行づつ処理している感じです。  
1行づつ見るので、行数が多いと処理に時間が掛かります。  
参考になれば幸いです!